diff --git a/composer.lock b/composer.lock index 2a912448..128b755a 100644 --- a/composer.lock +++ b/composer.lock @@ -225,6 +225,49 @@ ], "time": "2022-02-25T21:32:43+00:00" }, + { + "name": "doctrine/deprecations", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "8cffffb2218e01f3b370bf763e00e81697725259" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/8cffffb2218e01f3b370bf763e00e81697725259", + "reference": "8cffffb2218e01f3b370bf763e00e81697725259", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.1.0" + }, + "time": "2023-05-29T18:55:17+00:00" + }, { "name": "doctrine/instantiator", "version": "2.0.0", @@ -446,16 +489,16 @@ }, { "name": "netresearch/jsonmapper", - "version": "v4.1.0", + "version": "v4.2.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", "shasum": "" }, "require": { @@ -491,22 +534,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" }, - "time": "2022-12-08T20:46:14+00:00" + "time": "2023-04-09T17:37:40+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.4", + "version": "v4.15.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -547,9 +590,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, - "time": "2023-03-05T19:49:14+00:00" + "time": "2023-05-19T20:20:00+00:00" }, { "name": "phan/phan", @@ -853,24 +896,27 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -902,22 +948,68 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" }, - "time": "2022-10-14T12:47:21+00:00" + "time": "2023-05-30T18:13:47+00:00" }, { - "name": "phpstan/phpstan", - "version": "1.10.6", + "name": "phpstan/phpdoc-parser", + "version": "1.21.3", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a" + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "b0c366dd2cea79407d635839d25423ba07c55dd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b0c366dd2cea79407d635839d25423ba07c55dd6", + "reference": "b0c366dd2cea79407d635839d25423ba07c55dd6", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "nikic/php-parser": "^4.15", + "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", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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.21.3" + }, + "time": "2023-05-29T19:31:28+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.10.15", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", "shasum": "" }, "require": { @@ -946,8 +1038,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.10.6" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -963,7 +1058,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T16:55:12+00:00" + "time": "2023-05-09T15:28:01+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1285,16 +1380,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.5", + "version": "9.6.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5" + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", "shasum": "" }, "require": { @@ -1367,7 +1462,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" }, "funding": [ { @@ -1383,7 +1479,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T06:34:10+00:00" + "time": "2023-05-11T05:14:45+00:00" }, { "name": "psr/container", @@ -1854,16 +1950,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -1908,7 +2004,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -1916,7 +2012,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", @@ -2520,23 +2616,23 @@ }, { "name": "symfony/console", - "version": "v6.2.7", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45" + "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cbad09eb8925b6ad4fb721c7a179344dc4a19d45", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45", + "url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", + "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "conflict": { @@ -2558,12 +2654,6 @@ "symfony/process": "^5.4|^6.0", "symfony/var-dumper": "^5.4|^6.0" }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, "type": "library", "autoload": { "psr-4": { @@ -2591,12 +2681,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.2.7" + "source": "https://github.com/symfony/console/tree/v6.3.0" }, "funding": [ { @@ -2612,20 +2702,20 @@ "type": "tidelift" } ], - "time": "2023-02-25T17:00:03+00:00" + "time": "2023-05-29T12:49:39+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { @@ -2634,7 +2724,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2663,7 +2753,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.2.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" }, "funding": [ { @@ -2679,7 +2769,7 @@ "type": "tidelift" } ], - "time": "2023-03-01T10:25:55+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3096,16 +3186,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a" + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", "shasum": "" }, "require": { @@ -3115,13 +3205,10 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -3161,7 +3248,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" }, "funding": [ { @@ -3177,20 +3264,20 @@ "type": "tidelift" } ], - "time": "2023-03-01T10:32:47+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/string", - "version": "v6.2.7", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d" + "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/67b8c1eec78296b85dc1c7d9743830160218993d", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d", + "url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f", + "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f", "shasum": "" }, "require": { @@ -3201,13 +3288,13 @@ "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/http-client": "^5.4|^6.0", "symfony/intl": "^6.2", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", @@ -3247,7 +3334,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.7" + "source": "https://github.com/symfony/string/tree/v6.3.0" }, "funding": [ { @@ -3263,7 +3350,7 @@ "type": "tidelift" } ], - "time": "2023-02-24T10:42:00+00:00" + "time": "2023-03-21T21:06:29+00:00" }, { "name": "theseer/tokenizer", diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index fe203ab7..bfaccdaa 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -22,8 +22,10 @@ return array( 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), 'Phan\\' => array($vendorDir . '/phan/phan/src/Phan'), + 'PHPStan\\PhpDocParser\\' => array($vendorDir . '/phpstan/phpdoc-parser/src'), 'Microsoft\\PhpParser\\' => array($vendorDir . '/microsoft/tolerant-php-parser/src'), 'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'), + 'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'), 'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), 'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'), 'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 41f35c5d..6ae435f2 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -54,6 +54,7 @@ class ComposerStaticInitdd705c6e8ab22e0d642372dec7767718 'Psr\\Container\\' => 14, 'PhpParser\\' => 10, 'Phan\\' => 5, + 'PHPStan\\PhpDocParser\\' => 21, ), 'M' => array ( @@ -62,6 +63,7 @@ class ComposerStaticInitdd705c6e8ab22e0d642372dec7767718 'D' => array ( 'Doctrine\\Instantiator\\' => 22, + 'Doctrine\\Deprecations\\' => 22, 'DeepCopy\\' => 9, ), 'C' => @@ -143,6 +145,10 @@ class ComposerStaticInitdd705c6e8ab22e0d642372dec7767718 array ( 0 => __DIR__ . '/..' . '/phan/phan/src/Phan', ), + 'PHPStan\\PhpDocParser\\' => + array ( + 0 => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src', + ), 'Microsoft\\PhpParser\\' => array ( 0 => __DIR__ . '/..' . '/microsoft/tolerant-php-parser/src', @@ -151,6 +157,10 @@ class ComposerStaticInitdd705c6e8ab22e0d642372dec7767718 array ( 0 => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator', ), + 'Doctrine\\Deprecations\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations', + ), 'DeepCopy\\' => array ( 0 => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 7c46a5f6..3608fa66 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -227,6 +227,52 @@ ], "install-path": "./xdebug-handler" }, + { + "name": "doctrine/deprecations", + "version": "v1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "8cffffb2218e01f3b370bf763e00e81697725259" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/8cffffb2218e01f3b370bf763e00e81697725259", + "reference": "8cffffb2218e01f3b370bf763e00e81697725259", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "time": "2023-05-29T18:55:17+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.1.0" + }, + "install-path": "../doctrine/deprecations" + }, { "name": "doctrine/instantiator", "version": "2.0.0", @@ -460,17 +506,17 @@ }, { "name": "netresearch/jsonmapper", - "version": "v4.1.0", - "version_normalized": "4.1.0.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", "shasum": "" }, "require": { @@ -484,7 +530,7 @@ "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", "squizlabs/php_codesniffer": "~3.5" }, - "time": "2022-12-08T20:46:14+00:00", + "time": "2023-04-09T17:37:40+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -508,23 +554,23 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" }, "install-path": "../netresearch/jsonmapper" }, { "name": "nikic/php-parser", - "version": "v4.15.4", - "version_normalized": "4.15.4.0", + "version": "v4.15.5", + "version_normalized": "4.15.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -535,7 +581,7 @@ "ircmaxell/php-yacc": "^0.0.7", "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, - "time": "2023-03-05T19:49:14+00:00", + "time": "2023-05-19T20:20:00+00:00", "bin": [ "bin/php-parse" ], @@ -567,7 +613,7 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, "install-path": "../nikic/php-parser" }, @@ -888,25 +934,28 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", - "version_normalized": "1.6.2.0", + "version": "1.7.2", + "version_normalized": "1.7.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -914,7 +963,7 @@ "rector/rector": "^0.13.9", "vimeo/psalm": "^4.25" }, - "time": "2022-10-14T12:47:21+00:00", + "time": "2023-05-30T18:13:47+00:00", "type": "library", "extra": { "branch-alias": { @@ -940,23 +989,72 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" }, "install-path": "../phpdocumentor/type-resolver" }, { - "name": "phpstan/phpstan", - "version": "1.10.6", - "version_normalized": "1.10.6.0", + "name": "phpstan/phpdoc-parser", + "version": "1.21.3", + "version_normalized": "1.21.3.0", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a" + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "b0c366dd2cea79407d635839d25423ba07c55dd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b0c366dd2cea79407d635839d25423ba07c55dd6", + "reference": "b0c366dd2cea79407d635839d25423ba07c55dd6", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "nikic/php-parser": "^4.15", + "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", + "symfony/process": "^5.2" + }, + "time": "2023-05-29T19:31:28+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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.21.3" + }, + "install-path": "../phpstan/phpdoc-parser" + }, + { + "name": "phpstan/phpstan", + "version": "1.10.15", + "version_normalized": "1.10.15.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", "shasum": "" }, "require": { @@ -965,7 +1063,7 @@ "conflict": { "phpstan/phpstan-shim": "*" }, - "time": "2023-03-09T16:55:12+00:00", + "time": "2023-05-09T15:28:01+00:00", "bin": [ "phpstan", "phpstan.phar" @@ -987,8 +1085,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.10.6" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -1341,17 +1442,17 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.5", - "version_normalized": "9.6.5.0", + "version": "9.6.8", + "version_normalized": "9.6.8.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5" + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", "shasum": "" }, "require": { @@ -1387,7 +1488,7 @@ "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": "2023-03-09T06:34:10+00:00", + "time": "2023-05-11T05:14:45+00:00", "bin": [ "phpunit" ], @@ -1426,7 +1527,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" }, "funding": [ { @@ -1937,17 +2039,17 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", - "version_normalized": "4.0.4.0", + "version": "4.0.5", + "version_normalized": "4.0.5.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -1957,7 +2059,7 @@ "phpunit/phpunit": "^9.3", "symfony/process": "^4.2 || ^5" }, - "time": "2020-10-26T13:10:38+00:00", + "time": "2023-05-07T05:35:17+00:00", "type": "library", "extra": { "branch-alias": { @@ -1994,7 +2096,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -2636,24 +2738,24 @@ }, { "name": "symfony/console", - "version": "v6.2.7", - "version_normalized": "6.2.7.0", + "version": "v6.3.0", + "version_normalized": "6.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45" + "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cbad09eb8925b6ad4fb721c7a179344dc4a19d45", - "reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45", + "url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", + "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "conflict": { @@ -2675,13 +2777,7 @@ "symfony/process": "^5.4|^6.0", "symfony/var-dumper": "^5.4|^6.0" }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "time": "2023-02-25T17:00:03+00:00", + "time": "2023-05-29T12:49:39+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2710,12 +2806,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.2.7" + "source": "https://github.com/symfony/console/tree/v6.3.0" }, "funding": [ { @@ -2735,27 +2831,27 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.2.1", - "version_normalized": "3.2.1.0", + "version": "v3.3.0", + "version_normalized": "3.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2023-03-01T10:25:55+00:00", + "time": "2023-05-23T14:45:45+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2785,7 +2881,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.2.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" }, "funding": [ { @@ -3233,17 +3329,17 @@ }, { "name": "symfony/service-contracts", - "version": "v3.2.1", - "version_normalized": "3.2.1.0", + "version": "v3.3.0", + "version_normalized": "3.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a" + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a", - "reference": "a8c9cedf55f314f3a186041d19537303766df09a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", "shasum": "" }, "require": { @@ -3253,14 +3349,11 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, - "time": "2023-03-01T10:32:47+00:00", + "time": "2023-05-23T14:45:45+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -3301,7 +3394,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" }, "funding": [ { @@ -3321,17 +3414,17 @@ }, { "name": "symfony/string", - "version": "v6.2.7", - "version_normalized": "6.2.7.0", + "version": "v6.3.0", + "version_normalized": "6.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d" + "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/67b8c1eec78296b85dc1c7d9743830160218993d", - "reference": "67b8c1eec78296b85dc1c7d9743830160218993d", + "url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f", + "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f", "shasum": "" }, "require": { @@ -3342,16 +3435,16 @@ "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/http-client": "^5.4|^6.0", "symfony/intl": "^6.2", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, - "time": "2023-02-24T10:42:00+00:00", + "time": "2023-03-21T21:06:29+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3390,7 +3483,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.7" + "source": "https://github.com/symfony/string/tree/v6.3.0" }, "funding": [ { @@ -3593,6 +3686,7 @@ "composer/pcre", "composer/semver", "composer/xdebug-handler", + "doctrine/deprecations", "doctrine/instantiator", "felixfbecker/advanced-json-rpc", "microsoft/tolerant-php-parser", @@ -3605,6 +3699,7 @@ "phpdocumentor/reflection-common", "phpdocumentor/reflection-docblock", "phpdocumentor/type-resolver", + "phpstan/phpdoc-parser", "phpstan/phpstan", "phpunit/php-code-coverage", "phpunit/php-file-iterator", diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 51d778c6..118a15df 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '1cbe4e5c06aec83ca037690cb9621e39312b9247', + 'reference' => '513b115d5729d1001743baf12d8991cc385b20d9', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -13,7 +13,7 @@ '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '1cbe4e5c06aec83ca037690cb9621e39312b9247', + 'reference' => '513b115d5729d1001743baf12d8991cc385b20d9', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -46,6 +46,15 @@ 'aliases' => array(), 'dev_requirement' => true, ), + 'doctrine/deprecations' => array( + 'pretty_version' => 'v1.1.0', + 'version' => '1.1.0.0', + 'reference' => '8cffffb2218e01f3b370bf763e00e81697725259', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/deprecations', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'doctrine/instantiator' => array( 'pretty_version' => '2.0.0', 'version' => '2.0.0.0', @@ -83,18 +92,18 @@ 'dev_requirement' => true, ), 'netresearch/jsonmapper' => array( - 'pretty_version' => 'v4.1.0', - 'version' => '4.1.0.0', - 'reference' => 'cfa81ea1d35294d64adb9c68aa4cb9e92400e53f', + 'pretty_version' => 'v4.2.0', + 'version' => '4.2.0.0', + 'reference' => 'f60565f8c0566a31acf06884cdaa591867ecc956', 'type' => 'library', 'install_path' => __DIR__ . '/../netresearch/jsonmapper', 'aliases' => array(), 'dev_requirement' => true, ), 'nikic/php-parser' => array( - 'pretty_version' => 'v4.15.4', - 'version' => '4.15.4.0', - 'reference' => '6bb5176bc4af8bcb7d926f88718db9b96a2d4290', + 'pretty_version' => 'v4.15.5', + 'version' => '4.15.5.0', + 'reference' => '11e2663a5bc9db5d714eedb4277ee300403b4a9e', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), @@ -146,18 +155,27 @@ 'dev_requirement' => true, ), 'phpdocumentor/type-resolver' => array( - 'pretty_version' => '1.6.2', - 'version' => '1.6.2.0', - 'reference' => '48f445a408c131e38cab1c235aa6d2bb7a0bb20d', + 'pretty_version' => '1.7.2', + 'version' => '1.7.2.0', + 'reference' => 'b2fe4d22a5426f38e014855322200b97b5362c0d', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', 'aliases' => array(), 'dev_requirement' => true, ), + 'phpstan/phpdoc-parser' => array( + 'pretty_version' => '1.21.3', + 'version' => '1.21.3.0', + 'reference' => 'b0c366dd2cea79407d635839d25423ba07c55dd6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpstan/phpdoc-parser', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'phpstan/phpstan' => array( - 'pretty_version' => '1.10.6', - 'version' => '1.10.6.0', - 'reference' => '50d089a3e0904b0fe7e2cf2d4fd37d427d64235a', + 'pretty_version' => '1.10.15', + 'version' => '1.10.15.0', + 'reference' => '762c4dac4da6f8756eebb80e528c3a47855da9bd', 'type' => 'library', 'install_path' => __DIR__ . '/../phpstan/phpstan', 'aliases' => array(), @@ -209,9 +227,9 @@ 'dev_requirement' => true, ), 'phpunit/phpunit' => array( - 'pretty_version' => '9.6.5', - 'version' => '9.6.5.0', - 'reference' => '86e761949019ae83f49240b2f2123fb5ab3b2fc5', + 'pretty_version' => '9.6.8', + 'version' => '9.6.8.0', + 'reference' => '17d621b3aff84d0c8b62539e269e87d8d5baa76e', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/phpunit', 'aliases' => array(), @@ -296,9 +314,9 @@ 'dev_requirement' => true, ), 'sebastian/diff' => array( - 'pretty_version' => '4.0.4', - 'version' => '4.0.4.0', - 'reference' => '3461e3fccc7cfdfc2720be910d3bd73c69be590d', + 'pretty_version' => '4.0.5', + 'version' => '4.0.5.0', + 'reference' => '74be17022044ebaaecfdf0c5cd504fc9cd5a7131', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/diff', 'aliases' => array(), @@ -395,18 +413,18 @@ 'dev_requirement' => true, ), 'symfony/console' => array( - 'pretty_version' => 'v6.2.7', - 'version' => '6.2.7.0', - 'reference' => 'cbad09eb8925b6ad4fb721c7a179344dc4a19d45', + 'pretty_version' => 'v6.3.0', + 'version' => '6.3.0.0', + 'reference' => '8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/deprecation-contracts' => array( - 'pretty_version' => 'v3.2.1', - 'version' => '3.2.1.0', - 'reference' => 'e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e', + 'pretty_version' => 'v3.3.0', + 'version' => '3.3.0.0', + 'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), @@ -458,18 +476,18 @@ 'dev_requirement' => true, ), 'symfony/service-contracts' => array( - 'pretty_version' => 'v3.2.1', - 'version' => '3.2.1.0', - 'reference' => 'a8c9cedf55f314f3a186041d19537303766df09a', + 'pretty_version' => 'v3.3.0', + 'version' => '3.3.0.0', + 'reference' => '40da9cc13ec349d9e4966ce18b5fbcd724ab10a4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/string' => array( - 'pretty_version' => 'v6.2.7', - 'version' => '6.2.7.0', - 'reference' => '67b8c1eec78296b85dc1c7d9743830160218993d', + 'pretty_version' => 'v6.3.0', + 'version' => '6.3.0.0', + 'reference' => 'f2e190ee75ff0f5eced645ec0be5c66fac81f51f', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/string', 'aliases' => array(), diff --git a/vendor/doctrine/deprecations/LICENSE b/vendor/doctrine/deprecations/LICENSE new file mode 100644 index 00000000..156905cd --- /dev/null +++ b/vendor/doctrine/deprecations/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-2021 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/vendor/doctrine/deprecations/README.md b/vendor/doctrine/deprecations/README.md new file mode 100644 index 00000000..93caf83f --- /dev/null +++ b/vendor/doctrine/deprecations/README.md @@ -0,0 +1,157 @@ +# Doctrine Deprecations + +A small (side-effect free by default) layer on top of +`trigger_error(E_USER_DEPRECATED)` or PSR-3 logging. + +- no side-effects by default, making it a perfect fit for libraries that don't know how the error handler works they operate under +- options to avoid having to rely on error handlers global state by using PSR-3 logging +- deduplicate deprecation messages to avoid excessive triggering and reduce overhead + +We recommend to collect Deprecations using a PSR logger instead of relying on +the global error handler. + +## Usage from consumer perspective: + +Enable Doctrine deprecations to be sent to a PSR3 logger: + +```php +\Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger); +``` + +Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)` +messages by setting the `DOCTRINE_DEPRECATIONS` environment variable to `trigger`. +Alternatively, call: + +```php +\Doctrine\Deprecations\Deprecation::enableWithTriggerError(); +``` + +If you only want to enable deprecation tracking, without logging or calling `trigger_error` +then set the `DOCTRINE_DEPRECATIONS` environment variable to `track`. +Alternatively, call: + +```php +\Doctrine\Deprecations\Deprecation::enableTrackingDeprecations(); +``` + +Tracking is enabled with all three modes and provides access to all triggered +deprecations and their individual count: + +```php +$deprecations = \Doctrine\Deprecations\Deprecation::getTriggeredDeprecations(); + +foreach ($deprecations as $identifier => $count) { + echo $identifier . " was triggered " . $count . " times\n"; +} +``` + +### Suppressing Specific Deprecations + +Disable triggering about specific deprecations: + +```php +\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier"); +``` + +Disable all deprecations from a package + +```php +\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm"); +``` + +### Other Operations + +When used within PHPUnit or other tools that could collect multiple instances of the same deprecations +the deduplication can be disabled: + +```php +\Doctrine\Deprecations\Deprecation::withoutDeduplication(); +``` + +Disable deprecation tracking again: + +```php +\Doctrine\Deprecations\Deprecation::disable(); +``` + +## Usage from a library/producer perspective: + +When you want to unconditionally trigger a deprecation even when called +from the library itself then the `trigger` method is the way to go: + +```php +\Doctrine\Deprecations\Deprecation::trigger( + "doctrine/orm", + "https://link/to/deprecations-description", + "message" +); +``` + +If variable arguments are provided at the end, they are used with `sprintf` on +the message. + +```php +\Doctrine\Deprecations\Deprecation::trigger( + "doctrine/orm", + "https://github.com/doctrine/orm/issue/1234", + "message %s %d", + "foo", + 1234 +); +``` + +When you want to trigger a deprecation only when it is called by a function +outside of the current package, but not trigger when the package itself is the cause, +then use: + +```php +\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside( + "doctrine/orm", + "https://link/to/deprecations-description", + "message" +); +``` + +Based on the issue link each deprecation message is only triggered once per +request. + +A limited stacktrace is included in the deprecation message to find the +offending location. + +Note: A producer/library should never call `Deprecation::enableWith` methods +and leave the decision how to handle deprecations to application and +frameworks. + +## Usage in PHPUnit tests + +There is a `VerifyDeprecations` trait that you can use to make assertions on +the occurrence of deprecations within a test. + +```php +use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; + +class MyTest extends TestCase +{ + use VerifyDeprecations; + + public function testSomethingDeprecation() + { + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234'); + + triggerTheCodeWithDeprecation(); + } + + public function testSomethingDeprecationFixed() + { + $this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234'); + + triggerTheCodeWithoutDeprecation(); + } +} +``` + +## What is a deprecation identifier? + +An identifier for deprecations is just a link to any resource, most often a +Github Issue or Pull Request explaining the deprecation and potentially its +alternative. diff --git a/vendor/doctrine/deprecations/composer.json b/vendor/doctrine/deprecations/composer.json new file mode 100644 index 00000000..c79e38cd --- /dev/null +++ b/vendor/doctrine/deprecations/composer.json @@ -0,0 +1,32 @@ +{ + "name": "doctrine/deprecations", + "type": "library", + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "license": "MIT", + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3", + "doctrine/coding-standard": "^9" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "autoload": { + "psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"} + }, + "autoload-dev": { + "psr-4": { + "DeprecationTests\\": "test_fixtures/src", + "Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo" + } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php new file mode 100644 index 00000000..6c76d984 --- /dev/null +++ b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php @@ -0,0 +1,294 @@ + */ + private static $ignoredPackages = []; + + /** @var array */ + private static $ignoredLinks = []; + + /** @var bool */ + private static $deduplication = true; + + /** + * Trigger a deprecation for the given package and identfier. + * + * The link should point to a Github issue or Wiki entry detailing the + * deprecation. It is additionally used to de-duplicate the trigger of the + * same deprecation during a request. + * + * @param mixed $args + */ + public static function trigger(string $package, string $link, string $message, ...$args): void + { + $type = self::$type ?? self::getTypeFromEnv(); + + if ($type === self::TYPE_NONE) { + return; + } + + if (array_key_exists($link, self::$ignoredLinks)) { + self::$ignoredLinks[$link]++; + } else { + self::$ignoredLinks[$link] = 1; + } + + if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * Trigger a deprecation for the given package and identifier when called from outside. + * + * "Outside" means we assume that $package is currently installed as a + * dependency and the caller is not a file in that package. When $package + * is installed as a root package then deprecations triggered from the + * tests folder are also considered "outside". + * + * This deprecation method assumes that you are using Composer to install + * the dependency and are using the default /vendor/ folder and not a + * Composer plugin to change the install location. The assumption is also + * that $package is the exact composer packge name. + * + * Compared to {@link trigger()} this method causes some overhead when + * deprecation tracking is enabled even during deduplication, because it + * needs to call {@link debug_backtrace()} + * + * @param mixed $args + */ + public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void + { + $type = self::$type ?? self::getTypeFromEnv(); + + if ($type === self::TYPE_NONE) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + // first check that the caller is not from a tests folder, in which case we always let deprecations pass + if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) { + $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR; + + if (strpos($backtrace[0]['file'], $path) === false) { + return; + } + + if (strpos($backtrace[1]['file'], $path) !== false) { + return; + } + } + + if (array_key_exists($link, self::$ignoredLinks)) { + self::$ignoredLinks[$link]++; + } else { + self::$ignoredLinks[$link] = 1; + } + + if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * @param array $backtrace + */ + private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void + { + $type = self::$type ?? self::getTypeFromEnv(); + + if (($type & self::TYPE_PSR_LOGGER) > 0) { + $context = [ + 'file' => $backtrace[0]['file'], + 'line' => $backtrace[0]['line'], + 'package' => $package, + 'link' => $link, + ]; + + self::$logger->notice($message, $context); + } + + if (! (($type & self::TYPE_TRIGGER_ERROR) > 0)) { + return; + } + + $message .= sprintf( + ' (%s:%d called by %s:%d, %s, package %s)', + self::basename($backtrace[0]['file']), + $backtrace[0]['line'], + self::basename($backtrace[1]['file']), + $backtrace[1]['line'], + $link, + $package + ); + + @trigger_error($message, E_USER_DEPRECATED); + } + + /** + * A non-local-aware version of PHPs basename function. + */ + private static function basename(string $filename): string + { + $pos = strrpos($filename, DIRECTORY_SEPARATOR); + + if ($pos === false) { + return $filename; + } + + return substr($filename, $pos + 1); + } + + public static function enableTrackingDeprecations(): void + { + self::$type |= self::TYPE_TRACK_DEPRECATIONS; + } + + public static function enableWithTriggerError(): void + { + self::$type |= self::TYPE_TRIGGER_ERROR; + } + + public static function enableWithPsrLogger(LoggerInterface $logger): void + { + self::$type |= self::TYPE_PSR_LOGGER; + self::$logger = $logger; + } + + public static function withoutDeduplication(): void + { + self::$deduplication = false; + } + + public static function disable(): void + { + self::$type = self::TYPE_NONE; + self::$logger = null; + self::$deduplication = true; + + foreach (self::$ignoredLinks as $link => $count) { + self::$ignoredLinks[$link] = 0; + } + } + + public static function ignorePackage(string $packageName): void + { + self::$ignoredPackages[$packageName] = true; + } + + public static function ignoreDeprecations(string ...$links): void + { + foreach ($links as $link) { + self::$ignoredLinks[$link] = 0; + } + } + + public static function getUniqueTriggeredDeprecationsCount(): int + { + return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) { + return $carry + $count; + }, 0); + } + + /** + * Returns each triggered deprecation link identifier and the amount of occurrences. + * + * @return array + */ + public static function getTriggeredDeprecations(): array + { + return self::$ignoredLinks; + } + + /** + * @return self::TYPE_* + */ + private static function getTypeFromEnv(): int + { + switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) { + case 'trigger': + self::$type = self::TYPE_TRIGGER_ERROR; + break; + + case 'track': + self::$type = self::TYPE_TRACK_DEPRECATIONS; + break; + + default: + self::$type = self::TYPE_NONE; + break; + } + + return self::$type; + } +} diff --git a/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php new file mode 100644 index 00000000..4c3366a9 --- /dev/null +++ b/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php @@ -0,0 +1,66 @@ + */ + private $doctrineDeprecationsExpectations = []; + + /** @var array */ + private $doctrineNoDeprecationsExpectations = []; + + public function expectDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + public function expectNoDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + /** + * @before + */ + public function enableDeprecationTracking(): void + { + Deprecation::enableTrackingDeprecations(); + } + + /** + * @after + */ + public function verifyDeprecationsAreTriggered(): void + { + foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount > $expectation, + sprintf( + "Expected deprecation with identifier '%s' was not triggered by code executed in test.", + $identifier + ) + ); + } + + foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount === $expectation, + sprintf( + "Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.", + $identifier + ) + ); + } + } +} diff --git a/vendor/doctrine/deprecations/phpcs.xml b/vendor/doctrine/deprecations/phpcs.xml new file mode 100644 index 00000000..f115e43d --- /dev/null +++ b/vendor/doctrine/deprecations/phpcs.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + lib + tests + + + + + + diff --git a/vendor/netresearch/jsonmapper/.github/workflows/test.yml b/vendor/netresearch/jsonmapper/.github/workflows/test.yml new file mode 100644 index 00000000..76a8d654 --- /dev/null +++ b/vendor/netresearch/jsonmapper/.github/workflows/test.yml @@ -0,0 +1,46 @@ +name: JsonMapper tests +on: [push, workflow_dispatch] +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + php-versions: + - '7.1' + - '7.2' + - '7.3' + - '7.4' + - '8.0' + - '8.1' + - '8.2' + name: PHP ${{ matrix.php-versions }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + tools: composer + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ matrix.php-versions }}-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer-${{ matrix.php-versions }}- + + - name: Install dependencies + run: composer install --no-interaction --prefer-dist + + - name: Run unit tests + run: XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-text + + - name: Check codestyle + run: ./vendor/bin/phpcs --standard=PEAR src/ diff --git a/vendor/netresearch/jsonmapper/src/JsonMapper.php b/vendor/netresearch/jsonmapper/src/JsonMapper.php index fdb984f0..5ae3895b 100644 --- a/vendor/netresearch/jsonmapper/src/JsonMapper.php +++ b/vendor/netresearch/jsonmapper/src/JsonMapper.php @@ -75,7 +75,7 @@ class JsonMapper public $bStrictNullTypes = true; /** - * Allow mapping of private and proteted properties. + * Allow mapping of private and protected properties. * * @var boolean */ @@ -131,8 +131,8 @@ class JsonMapper /** * Map data all data in $json into the given $object instance. * - * @param object|array $json JSON object structure from json_decode() - * @param object $object Object to map $json data into + * @param object|array $json JSON object structure from json_decode() + * @param object|class-string $object Object to map $json data into * * @return mixed Mapped object is returned. * @see mapArray() @@ -145,13 +145,18 @@ class JsonMapper . ', ' . gettype($json) . ' given.' ); } - if (!is_object($object)) { + if (!is_object($object) && (!is_string($object) || !class_exists($object))) { throw new InvalidArgumentException( - 'JsonMapper::map() requires second argument to be an object' + 'JsonMapper::map() requires second argument to ' + . 'be an object or existing class name' . ', ' . gettype($object) . ' given.' ); } + if (is_string($object)) { + $object = $this->createInstance($object); + } + $strClassName = get_class($object); $rc = new ReflectionClass($object); $strNs = $rc->getNamespaceName(); @@ -177,10 +182,15 @@ class JsonMapper . ' in object of type ' . $strClassName ); } else if ($this->undefinedPropertyHandler !== null) { - call_user_func( + $undefinedPropertyKey = call_user_func( $this->undefinedPropertyHandler, $object, $key, $jvalue ); + + if (is_string($undefinedPropertyKey)) { + list($hasProperty, $accessor, $type, $isNullable) + = $this->inspectProperty($rc, $undefinedPropertyKey); + } } else { $this->log( 'info', @@ -188,7 +198,10 @@ class JsonMapper array('property' => $key, 'class' => $strClassName) ); } - continue; + + if (!$hasProperty) { + continue; + } } if ($accessor === null) { @@ -229,7 +242,9 @@ class JsonMapper } else if ($this->isObjectOfSameType($type, $jvalue)) { $this->setProperty($object, $accessor, $jvalue); continue; - } else if ($this->isSimpleType($type)) { + } else if ($this->isSimpleType($type) + && !(is_array($jvalue) && $this->hasVariadicArrayType($accessor)) + ) { if ($type === 'string' && is_object($jvalue)) { throw new JsonMapper_Exception( 'JSON property "' . $key . '" in class "' @@ -268,8 +283,11 @@ class JsonMapper } else { $array = $this->createInstance($proptype, false, $jvalue); } + } else if (is_array($jvalue) && $this->hasVariadicArrayType($accessor)) { + $array = array(); + $subtype = $type; } else { - if (is_a($type, 'ArrayObject', true)) { + if (is_a($type, 'ArrayAccess', true)) { $array = $this->createInstance($type, false, $jvalue); } } @@ -625,6 +643,8 @@ class JsonMapper } if ($accessor instanceof ReflectionProperty) { $accessor->setValue($object, $value); + } else if (is_array($value) && $this->hasVariadicArrayType($accessor)) { + $accessor->invoke($object, ...$value); } else { //setter method $accessor->invoke($object, $value); @@ -647,6 +667,12 @@ class JsonMapper $class, $useParameter = false, $jvalue = null ) { if ($useParameter) { + if (PHP_VERSION_ID >= 80100 + && is_subclass_of($class, \BackedEnum::class) + ) { + return $class::from($jvalue); + } + return new $class($jvalue); } else { $reflectClass = new ReflectionClass($class); @@ -758,6 +784,32 @@ class JsonMapper return substr($strType, -2) === '[]'; } + /** + * Returns true if accessor is a method and has only one parameter + * which is variadic. + * + * @param ReflectionMethod|ReflectionProperty|null $accessor accessor + * to set value + * + * @return bool + */ + protected function hasVariadicArrayType($accessor) + { + if (!$accessor instanceof ReflectionMethod) { + return false; + } + + $parameters = $accessor->getParameters(); + + if (count($parameters) !== 1) { + return false; + } + + $parameter = $parameters[0]; + + return $parameter->isVariadic(); + } + /** * Checks if the given type is nullable * diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php index de9aae7e..69f35332 100644 --- a/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php @@ -19,6 +19,8 @@ class Param implements PhpParser\Builder protected $variadic = false; + protected $flags = 0; + /** @var Node\AttributeGroup[] */ protected $attributeGroups = []; @@ -95,6 +97,50 @@ class Param implements PhpParser\Builder return $this; } + /** + * Makes the (promoted) parameter public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PUBLIC); + + return $this; + } + + /** + * Makes the (promoted) parameter protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PROTECTED); + + return $this; + } + + /** + * Makes the (promoted) parameter private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PRIVATE); + + return $this; + } + + /** + * Makes the (promoted) parameter readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_READONLY); + + return $this; + } + /** * Adds an attribute group. * @@ -116,7 +162,7 @@ class Param implements PhpParser\Builder public function getNode() : Node { return new Node\Param( new Node\Expr\Variable($this->name), - $this->default, $this->type, $this->byRef, $this->variadic, [], 0, $this->attributeGroups + $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups ); } } diff --git a/vendor/phpdocumentor/type-resolver/.yamllint.yaml b/vendor/phpdocumentor/type-resolver/.yamllint.yaml deleted file mode 100644 index 55695cd5..00000000 --- a/vendor/phpdocumentor/type-resolver/.yamllint.yaml +++ /dev/null @@ -1,65 +0,0 @@ -extends: "default" - -ignore: | - .build/ - .notes/ - vendor/ -rules: - braces: - max-spaces-inside-empty: 0 - max-spaces-inside: 1 - min-spaces-inside-empty: 0 - min-spaces-inside: 1 - brackets: - max-spaces-inside-empty: 0 - max-spaces-inside: 0 - min-spaces-inside-empty: 0 - min-spaces-inside: 0 - colons: - max-spaces-after: 1 - max-spaces-before: 0 - commas: - max-spaces-after: 1 - max-spaces-before: 0 - min-spaces-after: 1 - comments: - ignore-shebangs: true - min-spaces-from-content: 1 - require-starting-space: true - comments-indentation: "enable" - document-end: - present: false - document-start: - present: false - indentation: - check-multi-line-strings: false - indent-sequences: true - spaces: 2 - empty-lines: - max-end: 0 - max-start: 0 - max: 1 - empty-values: - forbid-in-block-mappings: true - forbid-in-flow-mappings: true - hyphens: - max-spaces-after: 2 - key-duplicates: "enable" - key-ordering: "disable" - line-length: "disable" - new-line-at-end-of-file: "enable" - new-lines: - type: "unix" - octal-values: - forbid-implicit-octal: true - quoted-strings: - quote-type: "double" - trailing-spaces: "enable" - truthy: - allowed-values: - - "false" - - "true" - -yaml-files: - - "*.yaml" - - "*.yml" diff --git a/vendor/phpdocumentor/type-resolver/composer-require-checker.json b/vendor/phpdocumentor/type-resolver/composer-require-checker.json deleted file mode 100644 index 137522df..00000000 --- a/vendor/phpdocumentor/type-resolver/composer-require-checker.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "symbol-whitelist" : [ - "null", "true", "false", - "static", "self", "parent", - "array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", "XSLTProcessor", - "T_NAME_QUALIFIED", "T_NAME_FULLY_QUALIFIED" - ], - "php-core-extensions" : [ - "Core", - "pcre", - "Reflection", - "tokenizer", - "SPL", - "standard" - ] -} diff --git a/vendor/phpdocumentor/type-resolver/composer.json b/vendor/phpdocumentor/type-resolver/composer.json index a7ae10f6..3138b4cc 100644 --- a/vendor/phpdocumentor/type-resolver/composer.json +++ b/vendor/phpdocumentor/type-resolver/composer.json @@ -11,7 +11,9 @@ ], "require": { "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13", + "doctrine/deprecations": "^1.0" }, "require-dev": { "ext-tokenizer": "*", @@ -20,7 +22,8 @@ "phpstan/phpstan-phpunit": "^1.1", "phpstan/extension-installer": "^1.1", "vimeo/psalm": "^4.25", - "rector/rector": "^0.13.9" + "rector/rector": "^0.13.9", + "phpbench/phpbench": "^1.2" }, "autoload": { "psr-4": { diff --git a/vendor/phpdocumentor/type-resolver/rector.php b/vendor/phpdocumentor/type-resolver/rector.php deleted file mode 100644 index b285d6cf..00000000 --- a/vendor/phpdocumentor/type-resolver/rector.php +++ /dev/null @@ -1,26 +0,0 @@ -paths([ - __DIR__ . '/src', - __DIR__ . '/tests/unit' - ]); - - // register a single rule - $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); - $rectorConfig->rule(Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector::class); - $rectorConfig->rule(Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector::class); - $rectorConfig->rule(Rector\PHPUnit\Rector\Class_\AddProphecyTraitRector::class); - $rectorConfig->importNames(); - - // define sets of rules - $rectorConfig->sets([ - LevelSetList::UP_TO_PHP_74 - ]); -}; diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.php new file mode 100644 index 00000000..48e66f01 --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.php @@ -0,0 +1,44 @@ +items = $items; + } + + public function underlyingType(): Type + { + return new Array_(new Mixed_(), new ArrayKey()); + } + + public function __toString(): string + { + return 'array{' . implode(', ', $this->items) . '}'; + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php new file mode 100644 index 00000000..56ab5dce --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php @@ -0,0 +1,62 @@ +key = $key; + $this->value = $value ?? new Mixed_(); + $this->optional = $optional; + } + + public function getKey(): ?string + { + return $this->key; + } + + public function getValue(): Type + { + return $this->value; + } + + public function isOptional(): bool + { + return $this->optional; + } + + public function __toString(): string + { + if ($this->key !== null) { + return sprintf( + '%s%s: %s', + $this->key, + $this->optional ? '?' : '', + (string) $this->value + ); + } + + return (string) $this->value; + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.php new file mode 100644 index 00000000..930dfdcf --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.php @@ -0,0 +1,53 @@ +owner = $owner; + $this->expression = $expression; + } + + public function getOwner(): Type + { + return $this->owner; + } + + public function getExpression(): string + { + return $this->expression; + } + + public function underlyingType(): Type + { + return new Mixed_(); + } + + public function __toString(): string + { + return sprintf('%s::%s', (string) $this->owner, $this->expression); + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php new file mode 100644 index 00000000..778374fe --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php @@ -0,0 +1,44 @@ +value = $value; + } + + public function getValue(): float + { + return $this->value; + } + + public function underlyingType(): Type + { + return new Float_(); + } + + public function __toString(): string + { + return (string) $this->value; + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php new file mode 100644 index 00000000..e2f34633 --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php @@ -0,0 +1,44 @@ +value = $value; + } + + public function getValue(): int + { + return $this->value; + } + + public function underlyingType(): Type + { + return new Integer(); + } + + public function __toString(): string + { + return (string) $this->value; + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php new file mode 100644 index 00000000..dd6a6531 --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php @@ -0,0 +1,50 @@ +valueType instanceof Mixed_) { + return 'non-empty-list'; + } + + return 'non-empty-list<' . $this->valueType . '>'; + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php new file mode 100644 index 00000000..10b1f516 --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php @@ -0,0 +1,46 @@ +value = $value; + } + + public function getValue(): string + { + return $this->value; + } + + public function underlyingType(): Type + { + return new String_(); + } + + public function __toString(): string + { + return sprintf('"%s"', $this->value); + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/TypeResolver.php b/vendor/phpdocumentor/type-resolver/src/TypeResolver.php index e5695b8e..58af0ace 100644 --- a/vendor/phpdocumentor/type-resolver/src/TypeResolver.php +++ b/vendor/phpdocumentor/type-resolver/src/TypeResolver.php @@ -13,27 +13,36 @@ declare(strict_types=1); namespace phpDocumentor\Reflection; -use ArrayIterator; +use Doctrine\Deprecations\Deprecation; use InvalidArgumentException; +use phpDocumentor\Reflection\PseudoTypes\ArrayShape; +use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem; use phpDocumentor\Reflection\PseudoTypes\CallableString; +use phpDocumentor\Reflection\PseudoTypes\ConstExpression; use phpDocumentor\Reflection\PseudoTypes\False_; +use phpDocumentor\Reflection\PseudoTypes\FloatValue; use phpDocumentor\Reflection\PseudoTypes\HtmlEscapedString; use phpDocumentor\Reflection\PseudoTypes\IntegerRange; +use phpDocumentor\Reflection\PseudoTypes\IntegerValue; use phpDocumentor\Reflection\PseudoTypes\List_; use phpDocumentor\Reflection\PseudoTypes\LiteralString; use phpDocumentor\Reflection\PseudoTypes\LowercaseString; use phpDocumentor\Reflection\PseudoTypes\NegativeInteger; +use phpDocumentor\Reflection\PseudoTypes\NonEmptyList; use phpDocumentor\Reflection\PseudoTypes\NonEmptyLowercaseString; use phpDocumentor\Reflection\PseudoTypes\NonEmptyString; use phpDocumentor\Reflection\PseudoTypes\Numeric_; use phpDocumentor\Reflection\PseudoTypes\NumericString; use phpDocumentor\Reflection\PseudoTypes\PositiveInteger; +use phpDocumentor\Reflection\PseudoTypes\StringValue; use phpDocumentor\Reflection\PseudoTypes\TraitString; use phpDocumentor\Reflection\PseudoTypes\True_; +use phpDocumentor\Reflection\Types\AggregatedType; use phpDocumentor\Reflection\Types\Array_; use phpDocumentor\Reflection\Types\ArrayKey; use phpDocumentor\Reflection\Types\Boolean; use phpDocumentor\Reflection\Types\Callable_; +use phpDocumentor\Reflection\Types\CallableParameter; use phpDocumentor\Reflection\Types\ClassString; use phpDocumentor\Reflection\Types\Collection; use phpDocumentor\Reflection\Types\Compound; @@ -57,46 +66,51 @@ use phpDocumentor\Reflection\Types\Static_; use phpDocumentor\Reflection\Types\String_; use phpDocumentor\Reflection\Types\This; use phpDocumentor\Reflection\Types\Void_; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode; +use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode; +use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; +use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; +use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode; +use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode; +use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode; +use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode; +use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; +use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; +use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; +use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; +use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode; +use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode; +use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; +use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; +use PHPStan\PhpDocParser\Lexer\Lexer; +use PHPStan\PhpDocParser\Parser\ConstExprParser; +use PHPStan\PhpDocParser\Parser\ParserException; +use PHPStan\PhpDocParser\Parser\TokenIterator; +use PHPStan\PhpDocParser\Parser\TypeParser; use RuntimeException; +use function array_filter; use function array_key_exists; -use function array_key_last; -use function array_pop; -use function array_values; +use function array_map; +use function array_reverse; use function class_exists; use function class_implements; -use function count; -use function current; +use function get_class; use function in_array; -use function is_numeric; -use function preg_split; +use function sprintf; use function strpos; use function strtolower; use function trim; -use const PREG_SPLIT_DELIM_CAPTURE; -use const PREG_SPLIT_NO_EMPTY; - final class TypeResolver { - /** @var string Definition of the ARRAY operator for types */ - private const OPERATOR_ARRAY = '[]'; - /** @var string Definition of the NAMESPACE operator in PHP */ private const OPERATOR_NAMESPACE = '\\'; - /** @var int the iterator parser is inside a compound context */ - private const PARSER_IN_COMPOUND = 0; - - /** @var int the iterator parser is inside a nullable expression context */ - private const PARSER_IN_NULLABLE = 1; - - /** @var int the iterator parser is inside an array expression context */ - private const PARSER_IN_ARRAY_EXPRESSION = 2; - - /** @var int the iterator parser is inside a collection expression context */ - private const PARSER_IN_COLLECTION_EXPRESSION = 3; - /** * @var array List of recognized keywords and unto which Value Object they map * @psalm-var array> @@ -142,10 +156,15 @@ final class TypeResolver 'iterable' => Iterable_::class, 'never' => Never_::class, 'list' => List_::class, + 'non-empty-list' => NonEmptyList::class, ]; /** @psalm-readonly */ private FqsenResolver $fqsenResolver; + /** @psalm-readonly */ + private TypeParser $typeParser; + /** @psalm-readonly */ + private Lexer $lexer; /** * Initializes this TypeResolver with the means to create and resolve Fqsen objects. @@ -153,6 +172,8 @@ final class TypeResolver public function __construct(?FqsenResolver $fqsenResolver = null) { $this->fqsenResolver = $fqsenResolver ?: new FqsenResolver(); + $this->typeParser = new TypeParser(new ConstExprParser()); + $this->lexer = new Lexer(); } /** @@ -165,9 +186,9 @@ final class TypeResolver * This method only works as expected if the namespace and aliases are set; * no dynamic reflection is being performed here. * + * @uses Context::getNamespace() to determine with what to prefix the type name. * @uses Context::getNamespaceAliases() to check whether the first part of the relative type name should not be * replaced with another namespace. - * @uses Context::getNamespace() to determine with what to prefix the type name. * * @param string $type The relative or absolute type. */ @@ -182,178 +203,219 @@ final class TypeResolver $context = new Context(''); } - // split the type string into tokens `|`, `?`, `<`, `>`, `,`, `(`, `)`, `[]`, '<', '>' and type names - $tokens = preg_split( - '/(\\||\\?|<|>|&|, ?|\\(|\\)|\\[\\]+)/', - $type, - -1, - PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE - ); + $tokens = $this->lexer->tokenize($type); + $tokenIterator = new TokenIterator($tokens); - if ($tokens === false) { - throw new InvalidArgumentException('Unable to split the type string "' . $type . '" into tokens'); - } + $ast = $this->parse($tokenIterator); + $type = $this->createType($ast, $context); - /** @var ArrayIterator $tokenIterator */ - $tokenIterator = new ArrayIterator($tokens); - - return $this->parseTypes($tokenIterator, $context, self::PARSER_IN_COMPOUND); + return $this->tryParseRemainingCompoundTypes($tokenIterator, $context, $type); } - /** - * Analyse each tokens and creates types - * - * @param ArrayIterator $tokens the iterator on tokens - * @param int $parserContext on of self::PARSER_* constants, indicating - * the context where we are in the parsing - */ - private function parseTypes(ArrayIterator $tokens, Context $context, int $parserContext): Type + public function createType(?TypeNode $type, Context $context): Type { - $types = []; - $token = ''; - $compoundToken = '|'; - while ($tokens->valid()) { - $token = $tokens->current(); - if ($token === null) { - throw new RuntimeException( - 'Unexpected nullable character' - ); - } + if ($type === null) { + return new Mixed_(); + } - if ($token === '|' || $token === '&') { - if (count($types) === 0) { + switch (get_class($type)) { + case ArrayTypeNode::class: + return new Array_( + $this->createType($type->type, $context) + ); + + case ArrayShapeNode::class: + return new ArrayShape( + ...array_map( + fn (ArrayShapeItemNode $item) => new ArrayShapeItem( + (string) $item->keyName, + $this->createType($item->valueType, $context), + $item->optional + ), + $type->items + ) + ); + + case CallableTypeNode::class: + return $this->createFromCallable($type, $context); + + case ConstTypeNode::class: + return $this->createFromConst($type, $context); + + case GenericTypeNode::class: + return $this->createFromGeneric($type, $context); + + case IdentifierTypeNode::class: + return $this->resolveSingleType($type->name, $context); + + case IntersectionTypeNode::class: + return new Intersection( + array_filter( + array_map( + function (TypeNode $nestedType) use ($context) { + $type = $this->createType($nestedType, $context); + if ($type instanceof AggregatedType) { + return new Expression($type); + } + + return $type; + }, + $type->types + ) + ) + ); + + case NullableTypeNode::class: + $nestedType = $this->createType($type->type, $context); + + return new Nullable($nestedType); + + case UnionTypeNode::class: + return new Compound( + array_filter( + array_map( + function (TypeNode $nestedType) use ($context) { + $type = $this->createType($nestedType, $context); + if ($type instanceof AggregatedType) { + return new Expression($type); + } + + return $type; + }, + $type->types + ) + ) + ); + + case ThisTypeNode::class: + return new This(); + + case ConditionalTypeNode::class: + case ConditionalTypeForParameterNode::class: + case OffsetAccessTypeNode::class: + default: + return new Mixed_(); + } + } + + private function createFromGeneric(GenericTypeNode $type, Context $context): Type + { + switch (strtolower($type->type->name)) { + case 'array': + return $this->createArray($type->genericTypes, $context); + + case 'class-string': + $subType = $this->createType($type->genericTypes[0], $context); + if (!$subType instanceof Object_ || $subType->getFqsen() === null) { throw new RuntimeException( - 'A type is missing before a type separator' + $subType . ' is not a class string' ); } - if ( - !in_array($parserContext, [ - self::PARSER_IN_COMPOUND, - self::PARSER_IN_ARRAY_EXPRESSION, - self::PARSER_IN_COLLECTION_EXPRESSION, - self::PARSER_IN_NULLABLE, - ], true) - ) { + return new ClassString( + $subType->getFqsen() + ); + + case 'interface-string': + $subType = $this->createType($type->genericTypes[0], $context); + if (!$subType instanceof Object_ || $subType->getFqsen() === null) { throw new RuntimeException( - 'Unexpected type separator' + $subType . ' is not a class string' ); } - $compoundToken = $token; - $tokens->next(); - } elseif ($token === '?') { - if ( - !in_array($parserContext, [ - self::PARSER_IN_COMPOUND, - self::PARSER_IN_ARRAY_EXPRESSION, - self::PARSER_IN_COLLECTION_EXPRESSION, - self::PARSER_IN_NULLABLE, - ], true) - ) { - throw new RuntimeException( - 'Unexpected nullable character' + return new InterfaceString( + $subType->getFqsen() + ); + + case 'list': + return new List_( + $this->createType($type->genericTypes[0], $context) + ); + + case 'non-empty-list': + return new NonEmptyList( + $this->createType($type->genericTypes[0], $context) + ); + + case 'int': + if (isset($type->genericTypes[1]) === false) { + throw new RuntimeException('int has not the correct format'); + } + + return new IntegerRange( + (string) $type->genericTypes[0], + (string) $type->genericTypes[1], + ); + + case 'iterable': + return new Iterable_( + ...array_reverse( + array_map( + fn (TypeNode $genericType) => $this->createType($genericType, $context), + $type->genericTypes + ) + ) + ); + + default: + $collectionType = $this->createType($type->type, $context); + if ($collectionType instanceof Object_ === false) { + throw new RuntimeException(sprintf('%s is not a collection', (string) $collectionType)); + } + + return new Collection( + $collectionType->getFqsen(), + ...array_reverse( + array_map( + fn (TypeNode $genericType) => $this->createType($genericType, $context), + $type->genericTypes + ) + ) + ); + } + } + + private function createFromCallable(CallableTypeNode $type, Context $context): Callable_ + { + return new Callable_( + array_map( + function (CallableTypeParameterNode $param) use ($context) { + return new CallableParameter( + $this->createType($param->type, $context), + $param->parameterName !== '' ? trim($param->parameterName, '$') : null, + $param->isReference, + $param->isVariadic, + $param->isOptional ); - } + }, + $type->parameters + ), + $this->createType($type->returnType, $context), + ); + } - $tokens->next(); - $type = $this->parseTypes($tokens, $context, self::PARSER_IN_NULLABLE); - $types[] = new Nullable($type); - } elseif ($token === '(') { - $tokens->next(); - $type = $this->parseTypes($tokens, $context, self::PARSER_IN_ARRAY_EXPRESSION); + private function createFromConst(ConstTypeNode $type, Context $context): Type + { + switch (true) { + case $type->constExpr instanceof ConstExprIntegerNode: + return new IntegerValue((int) $type->constExpr->value); - $token = $tokens->current(); - if ($token === null) { // Someone did not properly close their array expression .. - break; - } + case $type->constExpr instanceof ConstExprFloatNode: + return new FloatValue((float) $type->constExpr->value); - $tokens->next(); + case $type->constExpr instanceof ConstExprStringNode: + return new StringValue($type->constExpr->value); - $resolvedType = new Expression($type); - - $types[] = $resolvedType; - } elseif ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION && isset($token[0]) && $token[0] === ')') { - break; - } elseif ($token === '<') { - if (count($types) === 0) { - throw new RuntimeException( - 'Unexpected collection operator "<", class name is missing' - ); - } - - $classType = array_pop($types); - if ($classType !== null) { - if ((string) $classType === 'class-string') { - $types[] = $this->resolveClassString($tokens, $context); - } elseif ((string) $classType === 'int') { - $types[] = $this->resolveIntRange($tokens); - } elseif ((string) $classType === 'interface-string') { - $types[] = $this->resolveInterfaceString($tokens, $context); - } else { - $types[] = $this->resolveCollection($tokens, $classType, $context); - } - } - - $tokens->next(); - } elseif ( - $parserContext === self::PARSER_IN_COLLECTION_EXPRESSION - && ($token === '>' || trim($token) === ',') - ) { - break; - } elseif ($token === self::OPERATOR_ARRAY) { - $last = array_key_last($types); - if ($last === null) { - throw new InvalidArgumentException('Unexpected array operator'); - } - - $lastItem = $types[$last]; - if ($lastItem instanceof Expression) { - $lastItem = $lastItem->getValueType(); - } - - $types[$last] = new Array_($lastItem); - - $tokens->next(); - } else { - $types[] = $this->resolveSingleType($token, $context); - $tokens->next(); - } - } - - if ($token === '|' || $token === '&') { - throw new RuntimeException( - 'A type is missing after a type separator' - ); - } - - if (count($types) === 0) { - if ($parserContext === self::PARSER_IN_NULLABLE) { - throw new RuntimeException( - 'A type is missing after a nullable character' + case $type->constExpr instanceof ConstFetchNode: + return new ConstExpression( + $this->resolve($type->constExpr->className, $context), + $type->constExpr->name ); - } - if ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION) { - throw new RuntimeException( - 'A type is missing in an array expression' - ); - } - - if ($parserContext === self::PARSER_IN_COLLECTION_EXPRESSION) { - throw new RuntimeException( - 'A type is missing in a collection expression' - ); - } - } elseif (count($types) === 1) { - return current($types); + default: + throw new RuntimeException(sprintf('Unsupported constant type %s', get_class($type))); } - - if ($compoundToken === '|') { - return new Compound(array_values($types)); - } - - return new Intersection(array_values($types)); } /** @@ -475,244 +537,87 @@ final class TypeResolver return new Object_($this->fqsenResolver->resolve($type, $context)); } - /** - * Resolves class string - * - * @param ArrayIterator $tokens - */ - private function resolveClassString(ArrayIterator $tokens, Context $context): Type + /** @param TypeNode[] $typeNodes */ + private function createArray(array $typeNodes, Context $context): Array_ { - $tokens->next(); + $types = array_reverse( + array_map( + fn (TypeNode $node) => $this->createType($node, $context), + $typeNodes + ) + ); - $classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION); - - if (!$classType instanceof Object_ || $classType->getFqsen() === null) { - throw new RuntimeException( - $classType . ' is not a class string' - ); + if (isset($types[1]) === false) { + return new Array_(...$types); } - $token = $tokens->current(); - if ($token !== '>') { - if (empty($token)) { - throw new RuntimeException( - 'class-string: ">" is missing' - ); + if ($this->validArrayKeyType($types[1]) || $types[1] instanceof ArrayKey) { + return new Array_(...$types); + } + + if ($types[1] instanceof Compound && $types[1]->getIterator()->count() === 2) { + if ($this->validArrayKeyType($types[1]->get(0)) && $this->validArrayKeyType($types[1]->get(1))) { + return new Array_(...$types); } - - throw new RuntimeException( - 'Unexpected character "' . $token . '", ">" is missing' - ); } - return new ClassString($classType->getFqsen()); + throw new RuntimeException('An array can have only integers or strings as keys'); + } + + private function validArrayKeyType(?Type $type): bool + { + return $type instanceof String_ || $type instanceof Integer; + } + + private function parse(TokenIterator $tokenIterator): TypeNode + { + try { + $ast = $this->typeParser->parse($tokenIterator); + } catch (ParserException $e) { + throw new RuntimeException($e->getMessage(), 0, $e); + } + + return $ast; } /** - * Resolves integer ranges + * Will try to parse unsupported type notations by phpstan * - * @param ArrayIterator $tokens + * The phpstan parser doesn't support the illegal nullable combinations like this library does. + * This method will warn the user about those notations but for bc purposes we will still have it here. */ - private function resolveIntRange(ArrayIterator $tokens): Type + private function tryParseRemainingCompoundTypes(TokenIterator $tokenIterator, Context $context, Type $type): Type { - $tokens->next(); - - $token = ''; - $minValue = null; - $maxValue = null; - $commaFound = false; - $tokenCounter = 0; - while ($tokens->valid()) { - $tokenCounter++; - $token = $tokens->current(); - if ($token === null) { - throw new RuntimeException( - 'Unexpected nullable character' - ); - } - - $token = trim($token); - - if ($token === '>') { - break; - } - - if ($token === ',') { - $commaFound = true; - } - - if ($commaFound === false && $minValue === null) { - if (is_numeric($token) || $token === 'max' || $token === 'min') { - $minValue = $token; - } - } - - if ($commaFound === true && $maxValue === null) { - if (is_numeric($token) || $token === 'max' || $token === 'min') { - $maxValue = $token; - } - } - - $tokens->next(); - } - - if ($token !== '>') { - if (empty($token)) { - throw new RuntimeException( - 'interface-string: ">" is missing' - ); - } - - throw new RuntimeException( - 'Unexpected character "' . $token . '", ">" is missing' - ); - } - - if ($minValue === null || $maxValue === null || $tokenCounter > 4) { - throw new RuntimeException( - 'int has not the correct format' - ); - } - - return new IntegerRange($minValue, $maxValue); - } - - /** - * Resolves class string - * - * @param ArrayIterator $tokens - */ - private function resolveInterfaceString(ArrayIterator $tokens, Context $context): Type - { - $tokens->next(); - - $classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION); - - if (!$classType instanceof Object_ || $classType->getFqsen() === null) { - throw new RuntimeException( - $classType . ' is not a interface string' - ); - } - - $token = $tokens->current(); - if ($token !== '>') { - if (empty($token)) { - throw new RuntimeException( - 'interface-string: ">" is missing' - ); - } - - throw new RuntimeException( - 'Unexpected character "' . $token . '", ">" is missing' - ); - } - - return new InterfaceString($classType->getFqsen()); - } - - /** - * Resolves the collection values and keys - * - * @param ArrayIterator $tokens - * - * @return Array_|Iterable_|Collection - */ - private function resolveCollection(ArrayIterator $tokens, Type $classType, Context $context): Type - { - $isArray = ((string) $classType === 'array'); - $isIterable = ((string) $classType === 'iterable'); - $isList = ((string) $classType === 'list'); - - // allow only "array", "iterable" or class name before "<" if ( - !$isArray && !$isIterable && !$isList - && (!$classType instanceof Object_ || $classType->getFqsen() === null) + $tokenIterator->isCurrentTokenType(Lexer::TOKEN_UNION) || + $tokenIterator->isCurrentTokenType(Lexer::TOKEN_INTERSECTION) ) { - throw new RuntimeException( - $classType . ' is not a collection' + Deprecation::trigger( + 'phpdocumentor/type-resolver', + 'https://github.com/phpDocumentor/TypeResolver/issues/184', + 'Legacy nullable type detected, please update your code as + you are using nullable types in a docblock. support will be removed in v2.0.0', ); } - $tokens->next(); - - $valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION); - $keyType = null; - - $token = $tokens->current(); - if ($token !== null && trim($token) === ',' && !$isList) { - // if we have a comma, then we just parsed the key type, not the value type - $keyType = $valueType; - if ($isArray) { - // check the key type for an "array" collection. We allow only - // strings or integers. - if ( - !$keyType instanceof ArrayKey && - !$keyType instanceof String_ && - !$keyType instanceof Integer && - !$keyType instanceof Compound - ) { - throw new RuntimeException( - 'An array can have only integers or strings as keys' - ); - } - - if ($keyType instanceof Compound) { - foreach ($keyType->getIterator() as $item) { - if ( - !$item instanceof ArrayKey && - !$item instanceof String_ && - !$item instanceof Integer - ) { - throw new RuntimeException( - 'An array can have only integers or strings as keys' - ); - } - } - } + $continue = true; + while ($continue) { + $continue = false; + while ($tokenIterator->tryConsumeTokenType(Lexer::TOKEN_UNION)) { + $ast = $this->parse($tokenIterator); + $type2 = $this->createType($ast, $context); + $type = new Compound([$type, $type2]); + $continue = true; } - $tokens->next(); - // now let's parse the value type - $valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION); - } - - $token = $tokens->current(); - if ($token !== '>') { - if (empty($token)) { - throw new RuntimeException( - 'Collection: ">" is missing' - ); + while ($tokenIterator->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) { + $ast = $this->typeParser->parse($tokenIterator); + $type2 = $this->createType($ast, $context); + $type = new Intersection([$type, $type2]); + $continue = true; } - - throw new RuntimeException( - 'Unexpected character "' . $token . '", ">" is missing' - ); } - if ($isArray) { - return new Array_($valueType, $keyType); - } - - if ($isIterable) { - return new Iterable_($valueType, $keyType); - } - - if ($isList) { - return new List_($valueType); - } - - if ($classType instanceof Object_) { - return $this->makeCollectionFromObject($classType, $valueType, $keyType); - } - - throw new RuntimeException('Invalid $classType provided'); - } - - /** - * @psalm-pure - */ - private function makeCollectionFromObject(Object_ $object, Type $valueType, ?Type $keyType = null): Collection - { - return new Collection($object->getFqsen(), $valueType, $keyType); + return $type; } } diff --git a/vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php b/vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php index 257ed516..6f9e8795 100644 --- a/vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php +++ b/vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php @@ -106,7 +106,7 @@ abstract class AggregatedType implements Type, IteratorAggregate */ private function add(Type $type): void { - if ($type instanceof self) { + if ($type instanceof static) { foreach ($type->getIterator() as $subType) { $this->add($subType); } diff --git a/vendor/phpdocumentor/type-resolver/src/Types/CallableParameter.php b/vendor/phpdocumentor/type-resolver/src/Types/CallableParameter.php new file mode 100644 index 00000000..1a36d239 --- /dev/null +++ b/vendor/phpdocumentor/type-resolver/src/Types/CallableParameter.php @@ -0,0 +1,72 @@ +type = $type; + $this->isReference = $isReference; + $this->isVariadic = $isVariadic; + $this->isOptional = $isOptional; + $this->name = $name; + } + + public function getName(): ?string + { + return $this->name; + } + + public function getType(): Type + { + return $this->type; + } + + public function isReference(): bool + { + return $this->isReference; + } + + public function isVariadic(): bool + { + return $this->isVariadic; + } + + public function isOptional(): bool + { + return $this->isOptional; + } +} diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Callable_.php b/vendor/phpdocumentor/type-resolver/src/Types/Callable_.php index 4e67aa4a..20c57267 100644 --- a/vendor/phpdocumentor/type-resolver/src/Types/Callable_.php +++ b/vendor/phpdocumentor/type-resolver/src/Types/Callable_.php @@ -22,6 +22,30 @@ use phpDocumentor\Reflection\Type; */ final class Callable_ implements Type { + private ?Type $returnType; + /** @var CallableParameter[] */ + private array $parameters; + + /** + * @param CallableParameter[] $parameters + */ + public function __construct(array $parameters = [], ?Type $returnType = null) + { + $this->parameters = $parameters; + $this->returnType = $returnType; + } + + /** @return CallableParameter[] */ + public function getParameters(): array + { + return $this->parameters; + } + + public function getReturnType(): ?Type + { + return $this->returnType; + } + /** * Returns a rendered output of the Type as it would be used in a DocBlock. */ diff --git a/vendor/phpstan/phpdoc-parser/LICENSE b/vendor/phpstan/phpdoc-parser/LICENSE new file mode 100644 index 00000000..98a854e4 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Ondřej Mirtes + +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. \ No newline at end of file diff --git a/vendor/phpstan/phpdoc-parser/README.md b/vendor/phpstan/phpdoc-parser/README.md new file mode 100644 index 00000000..67312fd9 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/README.md @@ -0,0 +1,119 @@ +

PHPDoc Parser for PHPStan

+ +

+ Build Status + Latest Stable Version + License + PHPStan Enabled +

+ +This library `phpstan/phpdoc-parser` represents PHPDocs with an AST (Abstract Syntax Tree). It supports parsing and modifying PHPDocs. + +For the complete list of supported PHPDoc features check out PHPStan documentation. PHPStan is the main (but not the only) user of this library. + +* [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. + +## Installation + +``` +composer require phpstan/phpdoc-parser +``` + +## Basic usage + +```php +tokenize('/** @param Lorem $a */')); +$phpDocNode = $phpDocParser->parse($tokens); // PhpDocNode +$paramTags = $phpDocNode->getParamTagValues(); // ParamTagValueNode[] +echo $paramTags[0]->parameterName; // '$a' +echo $paramTags[0]->type; // IdentifierTypeNode - 'Lorem' +``` + +### Format-preserving printer + +This component can be used to modify the AST +and print it again as close as possible to the original. + +It's heavily inspired by format-preserving printer component in [nikic/PHP-Parser](https://github.com/nikic/PHP-Parser). + +```php + 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); + +$tokens = new TokenIterator($lexer->tokenize('/** @param Lorem $a */')); +$phpDocNode = $phpDocParser->parse($tokens); // PhpDocNode + +$cloningTraverser = new NodeTraverser([new CloningVisitor()]); + +/** @var PhpDocNode $newPhpDocNode */ +[$newPhpDocNode] = $cloningTraverser->traverse([$phpDocNode]); + +// change something in $newPhpDocNode +$newPhpDocNode->getParamTagValues()[0]->type = new IdentifierTypeNode('Ipsum'); + +// print changed PHPDoc +$printer = new Printer(); +$newPhpDoc = $printer->printFormatPreserving($newPhpDocNode, $phpDocNode, $tokens); +echo $newPhpDoc; // '/** @param Ipsum $a */' +``` + +## Code of Conduct + +This project adheres to a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project and its community, you are expected to uphold this code. + +## Building + +Initially you need to run `composer install`, or `composer update` in case you aren't working in a folder which was built before. + +Afterwards you can either run the whole build including linting and coding standards using + + make + +or run only tests using + + make tests diff --git a/vendor/phpstan/phpdoc-parser/composer.json b/vendor/phpstan/phpdoc-parser/composer.json new file mode 100644 index 00000000..30b879b7 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/composer.json @@ -0,0 +1,43 @@ +{ + "name": "phpstan/phpdoc-parser", + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "license": "MIT", + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "nikic/php-parser": "^4.15", + "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", + "symfony/process": "^5.2" + }, + "config": { + "platform": { + "php": "7.4.6" + }, + "sort-packages": true, + "allow-plugins": { + "phpstan/extension-installer": true + } + }, + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "autoload-dev": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "tests/PHPStan" + ] + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/vendor/phpstan/phpdoc-parser/phpstan-baseline.neon b/vendor/phpstan/phpdoc-parser/phpstan-baseline.neon new file mode 100644 index 00000000..04100fcd --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/phpstan-baseline.neon @@ -0,0 +1,31 @@ +parameters: + ignoreErrors: + - + message: "#^Method PHPStan\\\\PhpDocParser\\\\Ast\\\\ConstExpr\\\\QuoteAwareConstExprStringNode\\:\\:escapeDoubleQuotedString\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php + + - + message: "#^Cannot use array destructuring on array\\\\|int\\|string\\>\\|null\\.$#" + count: 1 + path: src/Ast/NodeTraverser.php + + - + message: "#^Strict comparison using \\=\\=\\= between 2 and 2 will always evaluate to true\\.$#" + count: 2 + path: src/Ast/NodeTraverser.php + + - + message: "#^Variable property access on PHPStan\\\\PhpDocParser\\\\Ast\\\\Node\\.$#" + count: 1 + path: src/Ast/NodeTraverser.php + + - + message: "#^Method PHPStan\\\\PhpDocParser\\\\Parser\\\\StringUnescaper\\:\\:parseEscapeSequences\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/Parser/StringUnescaper.php + + - + message: "#^Variable property access on PHPStan\\\\PhpDocParser\\\\Ast\\\\Node\\.$#" + count: 2 + path: src/Printer/Printer.php diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php b/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php new file mode 100644 index 00000000..2b9c10ec --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php @@ -0,0 +1,34 @@ +key = $key; + $this->value = $value; + } + + + public function __toString(): string + { + if ($this->key !== null) { + return sprintf('%s => %s', $this->key, $this->value); + + } + + return (string) $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php new file mode 100644 index 00000000..1f9def37 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php @@ -0,0 +1,30 @@ +items = $items; + } + + + public function __toString(): string + { + return '[' . implode(', ', $this->items) . ']'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php new file mode 100644 index 00000000..e6811277 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php @@ -0,0 +1,17 @@ +value = $value; + } + + + public function __toString(): string + { + return $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php new file mode 100644 index 00000000..5339bb5a --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php @@ -0,0 +1,26 @@ +value = $value; + } + + + public function __toString(): string + { + return $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php new file mode 100644 index 00000000..1859f03e --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php @@ -0,0 +1,10 @@ +value = $value; + } + + + public function __toString(): string + { + return $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php new file mode 100644 index 00000000..ec980320 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php @@ -0,0 +1,17 @@ +className = $className; + $this->name = $name; + } + + + public function __toString(): string + { + if ($this->className === '') { + return $this->name; + + } + + return "{$this->className}::{$this->name}"; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php new file mode 100644 index 00000000..f2792b1b --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php @@ -0,0 +1,78 @@ +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 = []; + + /** + * @param mixed $value + */ + public function setAttribute(string $key, $value): void + { + $this->attributes[$key] = $value; + } + + public function hasAttribute(string $key): bool + { + return array_key_exists($key, $this->attributes); + } + + /** + * @return mixed + */ + public function getAttribute(string $key) + { + if ($this->hasAttribute($key)) { + return $this->attributes[$key]; + } + + return null; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php b/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php new file mode 100644 index 00000000..63b25c37 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php @@ -0,0 +1,312 @@ + Visitors */ + private $visitors = []; + + /** @var bool Whether traversal should be stopped */ + private $stopTraversal; + + /** + * @param list $visitors + */ + public function __construct(array $visitors) + { + $this->visitors = $visitors; + } + + /** + * Traverses an array of nodes using the registered visitors. + * + * @param Node[] $nodes Array of nodes + * + * @return Node[] Traversed array of nodes + */ + public function traverse(array $nodes): array + { + $this->stopTraversal = false; + + foreach ($this->visitors as $visitor) { + $return = $visitor->beforeTraverse($nodes); + if ($return === null) { + continue; + } + + $nodes = $return; + } + + $nodes = $this->traverseArray($nodes); + + foreach ($this->visitors as $visitor) { + $return = $visitor->afterTraverse($nodes); + if ($return === null) { + continue; + } + + $nodes = $return; + } + + return $nodes; + } + + /** + * Recursively traverse a node. + * + * @param Node $node Node to traverse. + * + * @return Node Result of traversal (may be original node or new one) + */ + private function traverseNode(Node $node): Node + { + $subNodeNames = array_keys(get_object_vars($node)); + foreach ($subNodeNames as $name) { + $subNode =& $node->$name; + + if (is_array($subNode)) { + $subNode = $this->traverseArray($subNode); + if ($this->stopTraversal) { + break; + } + } elseif ($subNode instanceof Node) { + $traverseChildren = true; + $breakVisitorIndex = null; + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($subNode); + if ($return === null) { + continue; + } + + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif ($return === self::DONT_TRAVERSE_CHILDREN) { + $traverseChildren = false; + } elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) { + $traverseChildren = false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } else { + throw new LogicException( + 'enterNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($traverseChildren) { + $subNode = $this->traverseNode($subNode); + if ($this->stopTraversal) { + break; + } + } + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($subNode); + + if ($return !== null) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } elseif (is_array($return)) { + throw new LogicException( + 'leaveNode() may only return an array ' . + 'if the parent structure is an array' + ); + } else { + throw new LogicException( + 'leaveNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } + } + + return $node; + } + + /** + * Recursively traverse array (usually of nodes). + * + * @param mixed[] $nodes Array to traverse + * + * @return mixed[] Result of traversal (may be original array or changed one) + */ + private function traverseArray(array $nodes): array + { + $doNodes = []; + + foreach ($nodes as $i => &$node) { + if ($node instanceof Node) { + $traverseChildren = true; + $breakVisitorIndex = null; + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($node); + if ($return === null) { + continue; + } + + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (is_array($return)) { + $doNodes[] = [$i, $return]; + continue 2; + } elseif ($return === self::REMOVE_NODE) { + $doNodes[] = [$i, []]; + continue 2; + } elseif ($return === self::DONT_TRAVERSE_CHILDREN) { + $traverseChildren = false; + } elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) { + $traverseChildren = false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } else { + throw new LogicException( + 'enterNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($traverseChildren) { + $node = $this->traverseNode($node); + if ($this->stopTraversal) { + break; + } + } + + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($node); + + if ($return !== null) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (is_array($return)) { + $doNodes[] = [$i, $return]; + break; + } elseif ($return === self::REMOVE_NODE) { + $doNodes[] = [$i, []]; + break; + } elseif ($return === self::STOP_TRAVERSAL) { + $this->stopTraversal = true; + break 2; + } else { + throw new LogicException( + 'leaveNode() returned invalid value of type ' . gettype($return) + ); + } + } + + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } elseif (is_array($node)) { + throw new LogicException('Invalid node structure: Contains nested arrays'); + } + } + + if (count($doNodes) > 0) { + while ([$i, $replace] = array_pop($doNodes)) { + array_splice($nodes, $i, 1, $replace); + } + } + + return $nodes; + } + + private function ensureReplacementReasonable(Node $old, Node $new): void + { + if ($old instanceof TypeNode && !$new instanceof TypeNode) { + throw new LogicException(sprintf('Trying to replace TypeNode with %s', get_class($new))); + } + + if ($old instanceof ConstExprNode && !$new instanceof ConstExprNode) { + throw new LogicException(sprintf('Trying to replace ConstExprNode with %s', get_class($new))); + } + + if ($old instanceof PhpDocChildNode && !$new instanceof PhpDocChildNode) { + throw new LogicException(sprintf('Trying to replace PhpDocChildNode with %s', get_class($new))); + } + + if ($old instanceof PhpDocTagValueNode && !$new instanceof PhpDocTagValueNode) { + throw new LogicException(sprintf('Trying to replace PhpDocTagValueNode with %s', get_class($new))); + } + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php new file mode 100644 index 00000000..bf7d784e --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php @@ -0,0 +1,87 @@ + $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * NodeTraverser::REMOVE_NODE + * => $node is removed from the parent array + * * NodeTraverser::DONT_TRAVERSE_CHILDREN + * => Children of $node are not traversed. $node stays as-is + * * NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN + * => Further visitors for the current node are skipped, and its children are not + * traversed. $node stays as-is. + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return Node|Node[]|NodeTraverser::*|null Replacement node (or special return value) + */ + public function enterNode(Node $node); + + /** + * Called when leaving a node. + * + * Return value semantics: + * * null + * => $node stays as-is + * * NodeTraverser::REMOVE_NODE + * => $node is removed from the parent array + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return Node|Node[]|NodeTraverser::REMOVE_NODE|NodeTraverser::STOP_TRAVERSAL|null Replacement node (or special return value) + */ + public function leaveNode(Node $node); + + /** + * Called once after traversal. + * + * Return value semantics: + * * null: $nodes stays as-is + * * otherwise: $nodes is set to the return value + * + * @param Node[] $nodes Array of nodes + * + * @return Node[]|null Array of nodes + */ + public function afterTraverse(array $nodes): ?array; + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php new file mode 100644 index 00000000..7200f3af --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php @@ -0,0 +1,20 @@ +setAttribute(Attribute::ORIGINAL_NODE, $originalNode); + + return $node; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php new file mode 100644 index 00000000..cf4f5563 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php @@ -0,0 +1,50 @@ +type = $type; + $this->parameter = $parameter; + $this->method = $method; + $this->isNegated = $isNegated; + $this->isEquality = $isEquality; + $this->description = $description; + } + + + public function __toString(): string + { + $isNegated = $this->isNegated ? '!' : ''; + $isEquality = $this->isEquality ? '=' : ''; + return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->method}() {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php new file mode 100644 index 00000000..4fb31807 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php @@ -0,0 +1,50 @@ +type = $type; + $this->parameter = $parameter; + $this->property = $property; + $this->isNegated = $isNegated; + $this->isEquality = $isEquality; + $this->description = $description; + } + + + public function __toString(): string + { + $isNegated = $this->isNegated ? '!' : ''; + $isEquality = $this->isEquality ? '=' : ''; + return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->property} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php new file mode 100644 index 00000000..d6423f50 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php @@ -0,0 +1,46 @@ +type = $type; + $this->parameter = $parameter; + $this->isNegated = $isNegated; + $this->isEquality = $isEquality; + $this->description = $description; + } + + + public function __toString(): string + { + $isNegated = $this->isNegated ? '!' : ''; + $isEquality = $this->isEquality ? '=' : ''; + return trim("{$isNegated}{$isEquality}{$this->type} {$this->parameter} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php new file mode 100644 index 00000000..abf2f1a6 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php @@ -0,0 +1,27 @@ +description = $description; + } + + + public function __toString(): string + { + return trim($this->description); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php new file mode 100644 index 00000000..3bf53e13 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php @@ -0,0 +1,32 @@ +type = $type; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->type} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php new file mode 100644 index 00000000..026aa153 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php @@ -0,0 +1,26 @@ +value = $value; + } + + + public function __toString(): string + { + return $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php new file mode 100644 index 00000000..99043d91 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php @@ -0,0 +1,32 @@ +type = $type; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->type} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php new file mode 100644 index 00000000..ca7b4f20 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php @@ -0,0 +1,53 @@ +value = $value; + $this->exceptionArgs = [ + $exception->getCurrentTokenValue(), + $exception->getCurrentTokenType(), + $exception->getCurrentOffset(), + $exception->getExpectedTokenType(), + $exception->getExpectedTokenValue(), + $exception->getCurrentTokenLine(), + ]; + } + + public function __get(string $name): ?ParserException + { + if ($name !== 'exception') { + trigger_error(sprintf('Undefined property: %s::$%s', self::class, $name), E_USER_WARNING); + return null; + } + + return new ParserException(...$this->exceptionArgs); + } + + public function __toString(): string + { + return $this->value; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php new file mode 100644 index 00000000..211510be --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php @@ -0,0 +1,58 @@ +isStatic = $isStatic; + $this->returnType = $returnType; + $this->methodName = $methodName; + $this->parameters = $parameters; + $this->description = $description; + $this->templateTypes = $templateTypes; + } + + + public function __toString(): string + { + $static = $this->isStatic ? 'static ' : ''; + $returnType = $this->returnType !== null ? "{$this->returnType} " : ''; + $parameters = implode(', ', $this->parameters); + $description = $this->description !== '' ? " {$this->description}" : ''; + $templateTypes = count($this->templateTypes) > 0 ? '<' . implode(', ', $this->templateTypes) . '>' : ''; + return "{$static}{$returnType}{$this->methodName}{$templateTypes}({$parameters}){$description}"; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php new file mode 100644 index 00000000..7c17e44c --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php @@ -0,0 +1,49 @@ +type = $type; + $this->isReference = $isReference; + $this->isVariadic = $isVariadic; + $this->parameterName = $parameterName; + $this->defaultValue = $defaultValue; + } + + + public function __toString(): string + { + $type = $this->type !== null ? "{$this->type} " : ''; + $isReference = $this->isReference ? '&' : ''; + $isVariadic = $this->isVariadic ? '...' : ''; + $default = $this->defaultValue !== null ? " = {$this->defaultValue}" : ''; + return "{$type}{$isReference}{$isVariadic}{$this->parameterName}{$default}"; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php new file mode 100644 index 00000000..d9b7d78a --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php @@ -0,0 +1,32 @@ +type = $type; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->type} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php new file mode 100644 index 00000000..9f374bf1 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php @@ -0,0 +1,35 @@ +type = $type; + $this->parameterName = $parameterName; + $this->description = $description; + } + + public function __toString(): string + { + return trim("{$this->type} {$this->parameterName} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php new file mode 100644 index 00000000..f93af0ea --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php @@ -0,0 +1,46 @@ +type = $type; + $this->isReference = $isReference; + $this->isVariadic = $isVariadic; + $this->parameterName = $parameterName; + $this->description = $description; + } + + + public function __toString(): string + { + $reference = $this->isReference ? '&' : ''; + $variadic = $this->isVariadic ? '...' : ''; + return trim("{$this->type} {$reference}{$variadic}{$this->parameterName} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php new file mode 100644 index 00000000..6162f92d --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php @@ -0,0 +1,10 @@ +children = $children; + } + + + /** + * @return PhpDocTagNode[] + */ + public function getTags(): array + { + return array_filter($this->children, static function (PhpDocChildNode $child): bool { + return $child instanceof PhpDocTagNode; + }); + } + + + /** + * @return PhpDocTagNode[] + */ + public function getTagsByName(string $tagName): array + { + return array_filter($this->getTags(), static function (PhpDocTagNode $tag) use ($tagName): bool { + return $tag->name === $tagName; + }); + } + + + /** + * @return VarTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return ParamTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return TypelessParamTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return TemplateTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return ExtendsTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return ImplementsTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return UsesTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return ReturnTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return ThrowsTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return MixinTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return DeprecatedTagValueNode[] + */ + public function getDeprecatedTagValues(): array + { + return array_filter( + array_column($this->getTagsByName('@deprecated'), 'value'), + static function (PhpDocTagValueNode $value): bool { + return $value instanceof DeprecatedTagValueNode; + } + ); + } + + + /** + * @return PropertyTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return PropertyTagValueNode[] + */ + public function getPropertyReadTagValues(string $tagName = '@property-read'): array + { + return array_filter( + array_column($this->getTagsByName($tagName), 'value'), + static function (PhpDocTagValueNode $value): bool { + return $value instanceof PropertyTagValueNode; + } + ); + } + + + /** + * @return PropertyTagValueNode[] + */ + public function getPropertyWriteTagValues(string $tagName = '@property-write'): array + { + return array_filter( + array_column($this->getTagsByName($tagName), 'value'), + static function (PhpDocTagValueNode $value): bool { + return $value instanceof PropertyTagValueNode; + } + ); + } + + + /** + * @return MethodTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return TypeAliasTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return TypeAliasImportTagValueNode[] + */ + public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array + { + return array_filter( + array_column($this->getTagsByName($tagName), 'value'), + static function (PhpDocTagValueNode $value): bool { + return $value instanceof TypeAliasImportTagValueNode; + } + ); + } + + + /** + * @return AssertTagValueNode[] + */ + 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; + } + ); + } + + + /** + * @return AssertTagPropertyValueNode[] + */ + public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'): array + { + return array_filter( + array_column($this->getTagsByName($tagName), 'value'), + static function (PhpDocTagValueNode $value): bool { + return $value instanceof AssertTagPropertyValueNode; + } + ); + } + + + /** + * @return AssertTagMethodValueNode[] + */ + public function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): array + { + return array_filter( + array_column($this->getTagsByName($tagName), 'value'), + static function (PhpDocTagValueNode $value): bool { + return $value instanceof AssertTagMethodValueNode; + } + ); + } + + + /** + * @return SelfOutTagValueNode[] + */ + public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'): array + { + return array_filter( + array_column($this->getTagsByName($tagName), 'value'), + static function (PhpDocTagValueNode $value): bool { + return $value instanceof SelfOutTagValueNode; + } + ); + } + + + /** + * @return ParamOutTagValueNode[] + */ + 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; + } + ); + } + + + public function __toString(): string + { + $children = array_map( + static function (PhpDocChildNode $child): string { + $s = (string) $child; + return $s === '' ? '' : ' ' . $s; + }, + $this->children + ); + return "/**\n *" . implode("\n *", $children) . "\n */"; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php new file mode 100644 index 00000000..856cc3f1 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php @@ -0,0 +1,31 @@ +name = $name; + $this->value = $value; + } + + + public function __toString(): string + { + return trim("{$this->name} {$this->value}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php new file mode 100644 index 00000000..7723fa0c --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php @@ -0,0 +1,10 @@ +text = $text; + } + + + public function __toString(): string + { + return $this->text; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php new file mode 100644 index 00000000..046003d1 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php @@ -0,0 +1,36 @@ +type = $type; + $this->propertyName = $propertyName; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->type} {$this->propertyName} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php new file mode 100644 index 00000000..d53c8c75 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php @@ -0,0 +1,32 @@ +type = $type; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->type} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php new file mode 100644 index 00000000..83169aff --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php @@ -0,0 +1,32 @@ +type = $type; + $this->description = $description; + } + + + public function __toString(): string + { + return trim($this->type . ' ' . $this->description); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php new file mode 100644 index 00000000..1d3c70e4 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php @@ -0,0 +1,42 @@ +name = $name; + $this->bound = $bound; + $this->default = $default; + $this->description = $description; + } + + + public function __toString(): string + { + $bound = $this->bound !== null ? " of {$this->bound}" : ''; + $default = $this->default !== null ? " = {$this->default}" : ''; + return trim("{$this->name}{$bound}{$default} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php new file mode 100644 index 00000000..62d2aed3 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php @@ -0,0 +1,32 @@ +type = $type; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->type} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php new file mode 100644 index 00000000..ad6b85a5 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php @@ -0,0 +1,38 @@ +importedAlias = $importedAlias; + $this->importedFrom = $importedFrom; + $this->importedAs = $importedAs; + } + + public function __toString(): string + { + return trim( + "{$this->importedAlias} from {$this->importedFrom}" + . ($this->importedAs !== null ? " as {$this->importedAs}" : '') + ); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php new file mode 100644 index 00000000..4ccaaac4 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php @@ -0,0 +1,32 @@ +alias = $alias; + $this->type = $type; + } + + + public function __toString(): string + { + return trim("{$this->alias} {$this->type}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php new file mode 100644 index 00000000..8b982954 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php @@ -0,0 +1,41 @@ +isReference = $isReference; + $this->isVariadic = $isVariadic; + $this->parameterName = $parameterName; + $this->description = $description; + } + + + public function __toString(): string + { + $reference = $this->isReference ? '&' : ''; + $variadic = $this->isVariadic ? '...' : ''; + return trim("{$reference}{$variadic}{$this->parameterName} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php new file mode 100644 index 00000000..cd573d97 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php @@ -0,0 +1,32 @@ +type = $type; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("{$this->type} {$this->description}"); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php new file mode 100644 index 00000000..afb941a8 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php @@ -0,0 +1,36 @@ +type = $type; + $this->variableName = $variableName; + $this->description = $description; + } + + + public function __toString(): string + { + return trim("$this->type " . trim("{$this->variableName} {$this->description}")); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php new file mode 100644 index 00000000..660c6c9d --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php @@ -0,0 +1,49 @@ +keyName = $keyName; + $this->optional = $optional; + $this->valueType = $valueType; + } + + + public function __toString(): string + { + if ($this->keyName !== null) { + return sprintf( + '%s%s: %s', + (string) $this->keyName, + $this->optional ? '?' : '', + (string) $this->valueType + ); + } + + return (string) $this->valueType; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php new file mode 100644 index 00000000..806783f9 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php @@ -0,0 +1,48 @@ +items = $items; + $this->sealed = $sealed; + $this->kind = $kind; + } + + + public function __toString(): string + { + $items = $this->items; + + if (! $this->sealed) { + $items[] = '...'; + } + + return $this->kind . '{' . implode(', ', $items) . '}'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php new file mode 100644 index 00000000..d2031032 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php @@ -0,0 +1,34 @@ +type = $type; + } + + + public function __toString(): string + { + if ( + $this->type instanceof CallableTypeNode + || $this->type instanceof ConstTypeNode + || $this->type instanceof NullableTypeNode + ) { + return '(' . $this->type . ')[]'; + } + + return $this->type . '[]'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php new file mode 100644 index 00000000..e57e5f82 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php @@ -0,0 +1,43 @@ +identifier = $identifier; + $this->parameters = $parameters; + $this->returnType = $returnType; + } + + + public function __toString(): string + { + $returnType = $this->returnType; + if ($returnType instanceof self) { + $returnType = "({$returnType})"; + } + $parameters = implode(', ', $this->parameters); + return "{$this->identifier}({$parameters}): {$returnType}"; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php new file mode 100644 index 00000000..c78d4c7b --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php @@ -0,0 +1,48 @@ +type = $type; + $this->isReference = $isReference; + $this->isVariadic = $isVariadic; + $this->parameterName = $parameterName; + $this->isOptional = $isOptional; + } + + + public function __toString(): string + { + $type = "{$this->type} "; + $isReference = $this->isReference ? '&' : ''; + $isVariadic = $this->isVariadic ? '...' : ''; + $isOptional = $this->isOptional ? '=' : ''; + return trim("{$type}{$isReference}{$isVariadic}{$this->parameterName}") . $isOptional; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php new file mode 100644 index 00000000..fbfcae95 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php @@ -0,0 +1,49 @@ +parameterName = $parameterName; + $this->targetType = $targetType; + $this->if = $if; + $this->else = $else; + $this->negated = $negated; + } + + public function __toString(): string + { + return sprintf( + '(%s %s %s ? %s : %s)', + $this->parameterName, + $this->negated ? 'is not' : 'is', + $this->targetType, + $this->if, + $this->else + ); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php new file mode 100644 index 00000000..bfdb0db1 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php @@ -0,0 +1,49 @@ +subjectType = $subjectType; + $this->targetType = $targetType; + $this->if = $if; + $this->else = $else; + $this->negated = $negated; + } + + public function __toString(): string + { + return sprintf( + '(%s %s %s ? %s : %s)', + $this->subjectType, + $this->negated ? 'is not' : 'is', + $this->targetType, + $this->if, + $this->else + ); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php new file mode 100644 index 00000000..0096055b --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php @@ -0,0 +1,26 @@ +constExpr = $constExpr; + } + + public function __toString(): string + { + return $this->constExpr->__toString(); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php new file mode 100644 index 00000000..44e1d16d --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php @@ -0,0 +1,58 @@ +type = $type; + $this->genericTypes = $genericTypes; + $this->variances = $variances; + } + + + public function __toString(): string + { + $genericTypes = []; + + foreach ($this->genericTypes as $index => $type) { + $variance = $this->variances[$index] ?? self::VARIANCE_INVARIANT; + if ($variance === self::VARIANCE_INVARIANT) { + $genericTypes[] = (string) $type; + } elseif ($variance === self::VARIANCE_BIVARIANT) { + $genericTypes[] = '*'; + } else { + $genericTypes[] = sprintf('%s %s', $variance, $type); + } + } + + return $this->type . '<' . implode(', ', $genericTypes) . '>'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php new file mode 100644 index 00000000..29bac308 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php @@ -0,0 +1,26 @@ +name = $name; + } + + + public function __toString(): string + { + return $this->name; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php new file mode 100644 index 00000000..fd761cf7 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php @@ -0,0 +1,37 @@ +types = $types; + } + + + public function __toString(): string + { + return '(' . implode(' & ', array_map(static function (TypeNode $type): string { + if ($type instanceof NullableTypeNode) { + return '(' . $type . ')'; + } + + return (string) $type; + }, $this->types)) . ')'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php new file mode 100644 index 00000000..1ec47cf6 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php @@ -0,0 +1,38 @@ +exceptionArgs = [ + $exception->getCurrentTokenValue(), + $exception->getCurrentTokenType(), + $exception->getCurrentOffset(), + $exception->getExpectedTokenType(), + $exception->getExpectedTokenValue(), + $exception->getCurrentTokenLine(), + ]; + } + + public function getException(): ParserException + { + return new ParserException(...$this->exceptionArgs); + } + + public function __toString(): string + { + return '*Invalid type*'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php new file mode 100644 index 00000000..73f438cd --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php @@ -0,0 +1,26 @@ +type = $type; + } + + + public function __toString(): string + { + return '?' . $this->type; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php new file mode 100644 index 00000000..2f012406 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php @@ -0,0 +1,48 @@ +keyName = $keyName; + $this->optional = $optional; + $this->valueType = $valueType; + } + + + public function __toString(): string + { + if ($this->keyName !== null) { + return sprintf( + '%s%s: %s', + (string) $this->keyName, + $this->optional ? '?' : '', + (string) $this->valueType + ); + } + + return (string) $this->valueType; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php new file mode 100644 index 00000000..f418bc30 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php @@ -0,0 +1,31 @@ +items = $items; + } + + public function __toString(): string + { + $items = $this->items; + + return 'object{' . implode(', ', $items) . '}'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php new file mode 100644 index 00000000..39e83dfe --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php @@ -0,0 +1,37 @@ +type = $type; + $this->offset = $offset; + } + + public function __toString(): string + { + if ( + $this->type instanceof CallableTypeNode + || $this->type instanceof ConstTypeNode + || $this->type instanceof NullableTypeNode + ) { + return '(' . $this->type . ')[' . $this->offset . ']'; + } + + return $this->type . '[' . $this->offset . ']'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php new file mode 100644 index 00000000..d94e6f83 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php @@ -0,0 +1,17 @@ +types = $types; + } + + + public function __toString(): string + { + return '(' . implode(' | ', array_map(static function (TypeNode $type): string { + if ($type instanceof NullableTypeNode) { + return '(' . $type . ')'; + } + + return (string) $type; + }, $this->types)) . ')'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php b/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php new file mode 100644 index 00000000..ccae6bef --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php @@ -0,0 +1,181 @@ + '\'&\'', + self::TOKEN_UNION => '\'|\'', + self::TOKEN_INTERSECTION => '\'&\'', + self::TOKEN_NULLABLE => '\'?\'', + self::TOKEN_NEGATED => '\'!\'', + self::TOKEN_OPEN_PARENTHESES => '\'(\'', + self::TOKEN_CLOSE_PARENTHESES => '\')\'', + self::TOKEN_OPEN_ANGLE_BRACKET => '\'<\'', + self::TOKEN_CLOSE_ANGLE_BRACKET => '\'>\'', + self::TOKEN_OPEN_SQUARE_BRACKET => '\'[\'', + self::TOKEN_CLOSE_SQUARE_BRACKET => '\']\'', + self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'', + self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'', + self::TOKEN_COMMA => '\',\'', + self::TOKEN_COLON => '\':\'', + self::TOKEN_VARIADIC => '\'...\'', + self::TOKEN_DOUBLE_COLON => '\'::\'', + self::TOKEN_DOUBLE_ARROW => '\'=>\'', + self::TOKEN_ARROW => '\'->\'', + self::TOKEN_EQUAL => '\'=\'', + self::TOKEN_OPEN_PHPDOC => '\'/**\'', + self::TOKEN_CLOSE_PHPDOC => '\'*/\'', + self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG', + self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL', + self::TOKEN_FLOAT => 'TOKEN_FLOAT', + self::TOKEN_INTEGER => 'TOKEN_INTEGER', + self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING', + self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING', + self::TOKEN_IDENTIFIER => 'type', + self::TOKEN_THIS_VARIABLE => '\'$this\'', + self::TOKEN_VARIABLE => 'variable', + self::TOKEN_HORIZONTAL_WS => 'TOKEN_HORIZONTAL_WS', + self::TOKEN_OTHER => 'TOKEN_OTHER', + self::TOKEN_END => 'TOKEN_END', + self::TOKEN_WILDCARD => '*', + ]; + + public const VALUE_OFFSET = 0; + public const TYPE_OFFSET = 1; + public const LINE_OFFSET = 2; + + /** @var string|null */ + private $regexp; + + /** + * @return list + */ + public function tokenize(string $s): array + { + if ($this->regexp === null) { + $this->regexp = $this->generateRegexp(); + } + + preg_match_all($this->regexp, $s, $matches, PREG_SET_ORDER); + + $tokens = []; + $line = 1; + foreach ($matches as $match) { + $type = (int) $match['MARK']; + $tokens[] = [$match[0], $type, $line]; + if ($type !== self::TOKEN_PHPDOC_EOL) { + continue; + } + + $line++; + } + + $tokens[] = ['', self::TOKEN_END, $line]; + + return $tokens; + } + + + private function generateRegexp(): string + { + $patterns = [ + self::TOKEN_HORIZONTAL_WS => '[\\x09\\x20]++', + + self::TOKEN_IDENTIFIER => '(?:[\\\\]?+[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF-]*+)++', + self::TOKEN_THIS_VARIABLE => '\\$this(?![0-9a-z_\\x80-\\xFF])', + self::TOKEN_VARIABLE => '\\$[a-z_\\x80-\\xFF][0-9a-z_\\x80-\\xFF]*+', + + // '&' followed by TOKEN_VARIADIC, TOKEN_VARIABLE, TOKEN_EQUAL, TOKEN_EQUAL or TOKEN_CLOSE_PARENTHESES + self::TOKEN_REFERENCE => '&(?=\\s*+(?:[.,=)]|(?:\\$(?!this(?![0-9a-z_\\x80-\\xFF])))))', + self::TOKEN_UNION => '\\|', + self::TOKEN_INTERSECTION => '&', + self::TOKEN_NULLABLE => '\\?', + self::TOKEN_NEGATED => '!', + + self::TOKEN_OPEN_PARENTHESES => '\\(', + self::TOKEN_CLOSE_PARENTHESES => '\\)', + self::TOKEN_OPEN_ANGLE_BRACKET => '<', + self::TOKEN_CLOSE_ANGLE_BRACKET => '>', + self::TOKEN_OPEN_SQUARE_BRACKET => '\\[', + self::TOKEN_CLOSE_SQUARE_BRACKET => '\\]', + self::TOKEN_OPEN_CURLY_BRACKET => '\\{', + self::TOKEN_CLOSE_CURLY_BRACKET => '\\}', + + self::TOKEN_COMMA => ',', + self::TOKEN_VARIADIC => '\\.\\.\\.', + self::TOKEN_DOUBLE_COLON => '::', + self::TOKEN_DOUBLE_ARROW => '=>', + self::TOKEN_ARROW => '->', + self::TOKEN_EQUAL => '=', + self::TOKEN_COLON => ':', + + 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_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_WILDCARD => '\\*', + + // 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 . ')'; + } + + return '~' . implode('|', $patterns) . '~Asi'; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php new file mode 100644 index 00000000..b6db8a2c --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php @@ -0,0 +1,269 @@ +unescapeStrings = $unescapeStrings; + $this->quoteAwareConstExprString = $quoteAwareConstExprString; + $this->useLinesAttributes = $usedAttributes['lines'] ?? false; + $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; + } + + public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\ConstExpr\ConstExprNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_FLOAT)) { + $value = $tokens->currentTokenValue(); + $tokens->next(); + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprFloatNode(str_replace('_', '', $value)), + $startLine, + $startIndex + ); + } + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { + $value = $tokens->currentTokenValue(); + $tokens->next(); + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $value)), + $startLine, + $startIndex + ); + } + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { + $value = $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), + $startLine, + $startIndex + ); + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { + $identifier = $tokens->currentTokenValue(); + $tokens->next(); + + switch (strtolower($identifier)) { + case 'true': + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprTrueNode(), + $startLine, + $startIndex + ); + case 'false': + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprFalseNode(), + $startLine, + $startIndex + ); + case 'null': + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprNullNode(), + $startLine, + $startIndex + ); + case 'array': + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); + return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex); + } + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) { + $classConstantName = ''; + $lastType = null; + while (true) { + if ($lastType !== Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) { + $classConstantName .= $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + $lastType = Lexer::TOKEN_IDENTIFIER; + + continue; + } + + if ($lastType !== Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) { + $classConstantName .= '*'; + $lastType = Lexer::TOKEN_WILDCARD; + + if ($tokens->getSkippedHorizontalWhiteSpaceIfAny() !== '') { + break; + } + + continue; + } + + if ($lastType === null) { + // trigger parse error if nothing valid was consumed + $tokens->consumeTokenType(Lexer::TOKEN_WILDCARD); + } + + break; + } + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName), + $startLine, + $startIndex + ); + + } + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstFetchNode('', $identifier), + $startLine, + $startIndex + ); + + } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET, $startIndex); + } + + throw new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() + ); + } + + + private function parseArray(TokenIterator $tokens, int $endToken, int $startIndex): Ast\ConstExpr\ConstExprArrayNode + { + $items = []; + + $startLine = $tokens->currentTokenLine(); + + if (!$tokens->tryConsumeTokenType($endToken)) { + do { + $items[] = $this->parseArrayItem($tokens); + } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType($endToken)); + $tokens->consumeTokenType($endToken); + } + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprArrayNode($items), + $startLine, + $startIndex + ); + } + + + private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprArrayItemNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + $expr = $this->parse($tokens); + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_ARROW)) { + $key = $expr; + $value = $this->parse($tokens); + + } else { + $key = null; + $value = $expr; + } + + return $this->enrichWithAttributes( + $tokens, + new Ast\ConstExpr\ConstExprArrayItemNode($key, $value), + $startLine, + $startIndex + ); + } + + /** + * @template T of Ast\ConstExpr\ConstExprNode + * @param T $node + * @return T + */ + private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex): Ast\ConstExpr\ConstExprNode + { + $endLine = $tokens->currentTokenLine(); + $endIndex = $tokens->currentTokenIndex(); + if ($this->useLinesAttributes) { + $node->setAttribute(Ast\Attribute::START_LINE, $startLine); + $node->setAttribute(Ast\Attribute::END_LINE, $endLine); + } + + if ($this->useIndexAttributes) { + $tokensArray = $tokens->getTokens(); + $endIndex--; + if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $endIndex--; + } + + $node->setAttribute(Ast\Attribute::START_INDEX, $startIndex); + $node->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + } + + return $node; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php b/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php new file mode 100644 index 00000000..6ab5cc07 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php @@ -0,0 +1,106 @@ +currentTokenValue = $currentTokenValue; + $this->currentTokenType = $currentTokenType; + $this->currentOffset = $currentOffset; + $this->expectedTokenType = $expectedTokenType; + $this->expectedTokenValue = $expectedTokenValue; + $this->currentTokenLine = $currentTokenLine; + + parent::__construct(sprintf( + 'Unexpected token %s, expected %s%s at offset %d%s', + $this->formatValue($currentTokenValue), + Lexer::TOKEN_LABELS[$expectedTokenType], + $expectedTokenValue !== null ? sprintf(' (%s)', $this->formatValue($expectedTokenValue)) : '', + $currentOffset, + $currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine) + )); + } + + + public function getCurrentTokenValue(): string + { + return $this->currentTokenValue; + } + + + public function getCurrentTokenType(): int + { + return $this->currentTokenType; + } + + + public function getCurrentOffset(): int + { + return $this->currentOffset; + } + + + public function getExpectedTokenType(): int + { + return $this->expectedTokenType; + } + + + public function getExpectedTokenValue(): ?string + { + return $this->expectedTokenValue; + } + + + public function getCurrentTokenLine(): ?int + { + return $this->currentTokenLine; + } + + + private function formatValue(string $value): string + { + $json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE); + assert($json !== false); + + return $json; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php new file mode 100644 index 00000000..a6401b65 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php @@ -0,0 +1,724 @@ +typeParser = $typeParser; + $this->constantExprParser = $constantExprParser; + $this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription; + $this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes; + $this->useLinesAttributes = $usedAttributes['lines'] ?? false; + $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; + } + + + public function parse(TokenIterator $tokens): Ast\PhpDoc\PhpDocNode + { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PHPDOC); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $children = []; + + 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); + } + } + + try { + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC); + } catch (ParserException $e) { + $name = ''; + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + if (count($children) > 0) { + $lastChild = $children[count($children) - 1]; + if ($lastChild instanceof Ast\PhpDoc\PhpDocTagNode) { + $name = $lastChild->name; + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + } + } + + $tag = new Ast\PhpDoc\PhpDocTagNode( + $name, + $this->enrichWithAttributes( + $tokens, + new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e), + $startLine, + $startIndex + ) + ); + + $tokens->forwardToTheEnd(); + + 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); + } + + + private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode + { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + return $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex); + } + + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $text = $this->parseText($tokens); + + return $this->enrichWithAttributes($tokens, $text, $startLine, $startIndex); + } + + /** + * @template T of Ast\Node + * @param T $tag + * @return T + */ + private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex): Ast\Node + { + $endLine = $tokens->currentTokenLine(); + $endIndex = $tokens->currentTokenIndex(); + + if ($this->useLinesAttributes) { + $tag->setAttribute(Ast\Attribute::START_LINE, $startLine); + $tag->setAttribute(Ast\Attribute::END_LINE, $endLine); + } + + if ($this->useIndexAttributes) { + $tokensArray = $tokens->getTokens(); + $endIndex--; + if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $endIndex--; + } + + $tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex); + $tag->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + } + + return $tag; + } + + + private function parseText(TokenIterator $tokens): Ast\PhpDoc\PhpDocTextNode + { + $text = ''; + + while (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { + $text .= $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END); + + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { + break; + } + + $tokens->pushSavePoint(); + $tokens->next(); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)) { + $tokens->rollback(); + break; + } + + $tokens->dropSavePoint(); + $text .= "\n"; + } + + return new Ast\PhpDoc\PhpDocTextNode(trim($text, " \t")); + } + + + public function parseTag(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagNode + { + $tag = $tokens->currentTokenValue(); + $tokens->next(); + $value = $this->parseTagValue($tokens, $tag); + + return new Ast\PhpDoc\PhpDocTagNode($tag, $value); + } + + + public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\PhpDocTagValueNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + try { + $tokens->pushSavePoint(); + + switch ($tag) { + case '@param': + case '@phpstan-param': + case '@psalm-param': + $tagValue = $this->parseParamTagValue($tokens); + break; + + case '@var': + case '@phpstan-var': + case '@psalm-var': + $tagValue = $this->parseVarTagValue($tokens); + break; + + case '@return': + case '@phpstan-return': + case '@psalm-return': + $tagValue = $this->parseReturnTagValue($tokens); + break; + + case '@throws': + case '@phpstan-throws': + $tagValue = $this->parseThrowsTagValue($tokens); + break; + + case '@mixin': + $tagValue = $this->parseMixinTagValue($tokens); + break; + + case '@deprecated': + $tagValue = $this->parseDeprecatedTagValue($tokens); + break; + + case '@property': + case '@property-read': + case '@property-write': + case '@phpstan-property': + case '@phpstan-property-read': + case '@phpstan-property-write': + case '@psalm-property': + case '@psalm-property-read': + case '@psalm-property-write': + $tagValue = $this->parsePropertyTagValue($tokens); + break; + + case '@method': + case '@phpstan-method': + case '@psalm-method': + $tagValue = $this->parseMethodTagValue($tokens); + break; + + case '@template': + case '@phpstan-template': + case '@psalm-template': + case '@template-covariant': + case '@phpstan-template-covariant': + case '@psalm-template-covariant': + case '@template-contravariant': + case '@phpstan-template-contravariant': + case '@psalm-template-contravariant': + $tagValue = $this->parseTemplateTagValue($tokens, true); + break; + + case '@extends': + case '@phpstan-extends': + case '@template-extends': + $tagValue = $this->parseExtendsTagValue('@extends', $tokens); + break; + + case '@implements': + case '@phpstan-implements': + case '@template-implements': + $tagValue = $this->parseExtendsTagValue('@implements', $tokens); + break; + + case '@use': + case '@phpstan-use': + case '@template-use': + $tagValue = $this->parseExtendsTagValue('@use', $tokens); + break; + + case '@phpstan-type': + case '@psalm-type': + $tagValue = $this->parseTypeAliasTagValue($tokens); + break; + + case '@phpstan-import-type': + case '@psalm-import-type': + $tagValue = $this->parseTypeAliasImportTagValue($tokens); + break; + + case '@phpstan-assert': + case '@phpstan-assert-if-true': + case '@phpstan-assert-if-false': + case '@psalm-assert': + case '@psalm-assert-if-true': + case '@psalm-assert-if-false': + $tagValue = $this->parseAssertTagValue($tokens); + break; + + case '@phpstan-this-out': + case '@phpstan-self-out': + case '@psalm-this-out': + case '@psalm-self-out': + $tagValue = $this->parseSelfOutTagValue($tokens); + break; + + case '@param-out': + case '@phpstan-param-out': + case '@psalm-param-out': + $tagValue = $this->parseParamOutTagValue($tokens); + break; + + default: + $tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens)); + break; + } + + $tokens->dropSavePoint(); + + } catch (ParserException $e) { + $tokens->rollback(); + $tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens), $e); + } + + return $this->enrichWithAttributes($tokens, $tagValue, $startLine, $startIndex); + } + + + /** + * @return Ast\PhpDoc\ParamTagValueNode|Ast\PhpDoc\TypelessParamTagValueNode + */ + private function parseParamTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode + { + if ( + $tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE, Lexer::TOKEN_VARIADIC, Lexer::TOKEN_VARIABLE) + ) { + $type = null; + } else { + $type = $this->typeParser->parse($tokens); + } + + $isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE); + $isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC); + $parameterName = $this->parseRequiredVariableName($tokens); + $description = $this->parseOptionalDescription($tokens); + + if ($type !== null) { + return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference); + } + + return new Ast\PhpDoc\TypelessParamTagValueNode($isVariadic, $parameterName, $description, $isReference); + } + + + private function parseVarTagValue(TokenIterator $tokens): Ast\PhpDoc\VarTagValueNode + { + $type = $this->typeParser->parse($tokens); + $variableName = $this->parseOptionalVariableName($tokens); + $description = $this->parseOptionalDescription($tokens, $variableName === ''); + return new Ast\PhpDoc\VarTagValueNode($type, $variableName, $description); + } + + + private function parseReturnTagValue(TokenIterator $tokens): Ast\PhpDoc\ReturnTagValueNode + { + $type = $this->typeParser->parse($tokens); + $description = $this->parseOptionalDescription($tokens, true); + return new Ast\PhpDoc\ReturnTagValueNode($type, $description); + } + + + private function parseThrowsTagValue(TokenIterator $tokens): Ast\PhpDoc\ThrowsTagValueNode + { + $type = $this->typeParser->parse($tokens); + $description = $this->parseOptionalDescription($tokens, true); + return new Ast\PhpDoc\ThrowsTagValueNode($type, $description); + } + + private function parseMixinTagValue(TokenIterator $tokens): Ast\PhpDoc\MixinTagValueNode + { + $type = $this->typeParser->parse($tokens); + $description = $this->parseOptionalDescription($tokens, true); + return new Ast\PhpDoc\MixinTagValueNode($type, $description); + } + + private function parseDeprecatedTagValue(TokenIterator $tokens): Ast\PhpDoc\DeprecatedTagValueNode + { + $description = $this->parseOptionalDescription($tokens); + return new Ast\PhpDoc\DeprecatedTagValueNode($description); + } + + + private function parsePropertyTagValue(TokenIterator $tokens): Ast\PhpDoc\PropertyTagValueNode + { + $type = $this->typeParser->parse($tokens); + $parameterName = $this->parseRequiredVariableName($tokens); + $description = $this->parseOptionalDescription($tokens); + return new Ast\PhpDoc\PropertyTagValueNode($type, $parameterName, $description); + } + + + private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTagValueNode + { + $isStatic = $tokens->tryConsumeTokenValue('static'); + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $returnTypeOrMethodName = $this->typeParser->parse($tokens); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { + $returnType = $returnTypeOrMethodName; + $methodName = $tokens->currentTokenValue(); + $tokens->next(); + + } elseif ($returnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode) { + $returnType = $isStatic + ? $this->typeParser->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('static'), $startLine, $startIndex) + : null; + $methodName = $returnTypeOrMethodName->name; + $isStatic = false; + + } else { + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); // will throw exception + exit; + } + + $templateTypes = []; + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { + do { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $templateTypes[] = $this->enrichWithAttributes($tokens, $this->parseTemplateTagValue($tokens, false), $startLine, $startIndex); + } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); + } + + $parameters = []; + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { + $parameters[] = $this->parseMethodTagValueParameter($tokens); + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { + $parameters[] = $this->parseMethodTagValueParameter($tokens); + } + } + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); + + $description = $this->parseOptionalDescription($tokens); + return new Ast\PhpDoc\MethodTagValueNode($isStatic, $returnType, $methodName, $parameters, $description, $templateTypes); + } + + private function parseMethodTagValueParameter(TokenIterator $tokens): Ast\PhpDoc\MethodTagValueParameterNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + switch ($tokens->currentTokenType()) { + case Lexer::TOKEN_IDENTIFIER: + case Lexer::TOKEN_OPEN_PARENTHESES: + case Lexer::TOKEN_NULLABLE: + $parameterType = $this->typeParser->parse($tokens); + break; + + default: + $parameterType = null; + } + + $isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE); + $isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC); + + $parameterName = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) { + $defaultValue = $this->constantExprParser->parse($tokens); + + } else { + $defaultValue = null; + } + + return $this->enrichWithAttributes( + $tokens, + new Ast\PhpDoc\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue), + $startLine, + $startIndex + ); + } + + private function parseTemplateTagValue(TokenIterator $tokens, bool $parseDescription): Ast\PhpDoc\TemplateTagValueNode + { + $name = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + + if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) { + $bound = $this->typeParser->parse($tokens); + + } else { + $bound = null; + } + + if ($tokens->tryConsumeTokenValue('=')) { + $default = $this->typeParser->parse($tokens); + } else { + $default = null; + } + + if ($parseDescription) { + $description = $this->parseOptionalDescription($tokens); + } else { + $description = ''; + } + + return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default); + } + + private function parseExtendsTagValue(string $tagName, TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $baseType = new IdentifierTypeNode($tokens->currentTokenValue()); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + + $type = $this->typeParser->parseGeneric( + $tokens, + $this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex) + ); + + $description = $this->parseOptionalDescription($tokens); + + switch ($tagName) { + case '@extends': + return new Ast\PhpDoc\ExtendsTagValueNode($type, $description); + case '@implements': + return new Ast\PhpDoc\ImplementsTagValueNode($type, $description); + case '@use': + return new Ast\PhpDoc\UsesTagValueNode($type, $description); + } + + throw new ShouldNotHappenException(); + } + + private function parseTypeAliasTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeAliasTagValueNode + { + $alias = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + + // support 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() + ); + } + } + + 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); + } + + private function parseTypeAliasImportTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeAliasImportTagValueNode + { + $importedAlias = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + + $tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'from'); + + $identifierStartLine = $tokens->currentTokenLine(); + $identifierStartIndex = $tokens->currentTokenIndex(); + $importedFrom = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + $importedFromType = $this->enrichWithAttributes( + $tokens, + new IdentifierTypeNode($importedFrom), + $identifierStartLine, + $identifierStartIndex + ); + + $importedAs = null; + if ($tokens->tryConsumeTokenValue('as')) { + $importedAs = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + } + + return new Ast\PhpDoc\TypeAliasImportTagValueNode($importedAlias, $importedFromType, $importedAs); + } + + /** + * @return Ast\PhpDoc\AssertTagValueNode|Ast\PhpDoc\AssertTagPropertyValueNode|Ast\PhpDoc\AssertTagMethodValueNode + */ + private function parseAssertTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagValueNode + { + $isNegated = $tokens->tryConsumeTokenType(Lexer::TOKEN_NEGATED); + $isEquality = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); + $type = $this->typeParser->parse($tokens); + $parameter = $this->parseAssertParameter($tokens); + $description = $this->parseOptionalDescription($tokens); + + if (array_key_exists('method', $parameter)) { + return new Ast\PhpDoc\AssertTagMethodValueNode($type, $parameter['parameter'], $parameter['method'], $isNegated, $description, $isEquality); + } elseif (array_key_exists('property', $parameter)) { + return new Ast\PhpDoc\AssertTagPropertyValueNode($type, $parameter['parameter'], $parameter['property'], $isNegated, $description, $isEquality); + } + + return new Ast\PhpDoc\AssertTagValueNode($type, $parameter['parameter'], $isNegated, $description, $isEquality); + } + + /** + * @return array{parameter: string}|array{parameter: string, property: string}|array{parameter: string, method: string} + */ + private function parseAssertParameter(TokenIterator $tokens): array + { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) { + $parameter = '$this'; + $requirePropertyOrMethod = true; + $tokens->next(); + } else { + $parameter = $tokens->currentTokenValue(); + $requirePropertyOrMethod = false; + $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); + } + + if ($requirePropertyOrMethod || $tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) { + $tokens->consumeTokenType(Lexer::TOKEN_ARROW); + + $propertyOrMethod = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); + + return ['parameter' => $parameter, 'method' => $propertyOrMethod]; + } + + return ['parameter' => $parameter, 'property' => $propertyOrMethod]; + } + + return ['parameter' => $parameter]; + } + + private function parseSelfOutTagValue(TokenIterator $tokens): Ast\PhpDoc\SelfOutTagValueNode + { + $type = $this->typeParser->parse($tokens); + $description = $this->parseOptionalDescription($tokens); + + return new Ast\PhpDoc\SelfOutTagValueNode($type, $description); + } + + private function parseParamOutTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamOutTagValueNode + { + $type = $this->typeParser->parse($tokens); + $parameterName = $this->parseRequiredVariableName($tokens); + $description = $this->parseOptionalDescription($tokens); + + return new Ast\PhpDoc\ParamOutTagValueNode($type, $parameterName, $description); + } + + private function parseOptionalVariableName(TokenIterator $tokens): string + { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) { + $parameterName = $tokens->currentTokenValue(); + $tokens->next(); + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) { + $parameterName = '$this'; + $tokens->next(); + + } else { + $parameterName = ''; + } + + return $parameterName; + } + + + private function parseRequiredVariableName(TokenIterator $tokens): string + { + $parameterName = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); + + return $parameterName; + } + + private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken = false): string + { + if ($limitStartToken) { + foreach (self::DISALLOWED_DESCRIPTION_START_TOKENS as $disallowedStartToken) { + if (!$tokens->isCurrentTokenType($disallowedStartToken)) { + continue; + } + + $tokens->consumeTokenType(Lexer::TOKEN_OTHER); // will throw exception + } + + if ( + $this->requireWhitespaceBeforeDescription + && !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END) + && !$tokens->isPrecededByHorizontalWhitespace() + ) { + $tokens->consumeTokenType(Lexer::TOKEN_HORIZONTAL_WS); // will throw exception + } + } + + return $this->parseText($tokens)->text; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php b/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php new file mode 100644 index 00000000..70524055 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php @@ -0,0 +1,96 @@ + '\\', + 'n' => "\n", + 'r' => "\r", + 't' => "\t", + 'f' => "\f", + 'v' => "\v", + 'e' => "\x1B", + ]; + + public static function unescapeString(string $string): string + { + $quote = $string[0]; + + if ($quote === '\'') { + return str_replace( + ['\\\\', '\\\''], + ['\\', '\''], + substr($string, 1, -1) + ); + } + + return self::parseEscapeSequences(substr($string, 1, -1), '"'); + } + + /** + * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L90-L130 + */ + private static function parseEscapeSequences(string $str, string $quote): string + { + $str = str_replace('\\' . $quote, $quote, $str); + + return preg_replace_callback( + '~\\\\([\\\\nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u\{([0-9a-fA-F]+)\})~', + static function ($matches) { + $str = $matches[1]; + + if (isset(self::REPLACEMENTS[$str])) { + return self::REPLACEMENTS[$str]; + } + if ($str[0] === 'x' || $str[0] === 'X') { + return chr((int) hexdec(substr($str, 1))); + } + if ($str[0] === 'u') { + return self::codePointToUtf8((int) hexdec($matches[2])); + } + + return chr((int) octdec($str)); + }, + $str + ); + } + + /** + * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L132-L154 + */ + private static function codePointToUtf8(int $num): string + { + if ($num <= 0x7F) { + return chr($num); + } + if ($num <= 0x7FF) { + return chr(($num >> 6) + 0xC0) + . chr(($num & 0x3F) + 0x80); + } + if ($num <= 0xFFFF) { + return chr(($num >> 12) + 0xE0) + . chr((($num >> 6) & 0x3F) + 0x80) + . chr(($num & 0x3F) + 0x80); + } + if ($num <= 0x1FFFFF) { + return chr(($num >> 18) + 0xF0) + . chr((($num >> 12) & 0x3F) + 0x80) + . chr((($num >> 6) & 0x3F) + 0x80) + . chr(($num & 0x3F) + 0x80); + } + + // Invalid UTF-8 codepoint escape sequence: Codepoint too large + return "\xef\xbf\xbd"; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php b/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php new file mode 100644 index 00000000..4348ab79 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php @@ -0,0 +1,331 @@ + */ + private $tokens; + + /** @var int */ + private $index; + + /** @var int[] */ + private $savePoints = []; + + /** + * @param list $tokens + */ + public function __construct(array $tokens, int $index = 0) + { + $this->tokens = $tokens; + $this->index = $index; + + if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== Lexer::TOKEN_HORIZONTAL_WS) { + return; + } + + $this->index++; + } + + + /** + * @return list + */ + public function getTokens(): array + { + return $this->tokens; + } + + + public function getContentBetween(int $startPos, int $endPos): string + { + if ($startPos < 0 || $endPos > count($this->tokens)) { + throw new LogicException(); + } + + $content = ''; + for ($i = $startPos; $i < $endPos; $i++) { + $content .= $this->tokens[$i][Lexer::VALUE_OFFSET]; + } + + return $content; + } + + + public function getTokenCount(): int + { + return count($this->tokens); + } + + + public function currentTokenValue(): string + { + return $this->tokens[$this->index][Lexer::VALUE_OFFSET]; + } + + + public function currentTokenType(): int + { + return $this->tokens[$this->index][Lexer::TYPE_OFFSET]; + } + + + public function currentTokenOffset(): int + { + $offset = 0; + for ($i = 0; $i < $this->index; $i++) { + $offset += strlen($this->tokens[$i][Lexer::VALUE_OFFSET]); + } + + return $offset; + } + + + public function currentTokenLine(): int + { + return $this->tokens[$this->index][Lexer::LINE_OFFSET]; + } + + + public function currentTokenIndex(): int + { + return $this->index; + } + + + public function isCurrentTokenValue(string $tokenValue): bool + { + return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue; + } + + + public function isCurrentTokenType(int ...$tokenType): bool + { + return in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, true); + } + + + public function isPrecededByHorizontalWhitespace(): bool + { + return ($this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] ?? -1) === Lexer::TOKEN_HORIZONTAL_WS; + } + + + /** + * @throws ParserException + */ + public function consumeTokenType(int $tokenType): void + { + if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) { + $this->throwError($tokenType); + } + + $this->index++; + + if (($this->tokens[$this->index][Lexer::TYPE_OFFSET] ?? -1) !== Lexer::TOKEN_HORIZONTAL_WS) { + return; + } + + $this->index++; + } + + + /** + * @throws ParserException + */ + public function consumeTokenValue(int $tokenType, string $tokenValue): void + { + if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType || $this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) { + $this->throwError($tokenType, $tokenValue); + } + + $this->index++; + + if (($this->tokens[$this->index][Lexer::TYPE_OFFSET] ?? -1) !== Lexer::TOKEN_HORIZONTAL_WS) { + return; + } + + $this->index++; + } + + + /** @phpstan-impure */ + public function tryConsumeTokenValue(string $tokenValue): bool + { + if ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) { + return false; + } + + $this->index++; + + if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $this->index++; + } + + return true; + } + + + /** @phpstan-impure */ + public function tryConsumeTokenType(int $tokenType): bool + { + if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) { + return false; + } + + $this->index++; + + if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $this->index++; + } + + return true; + } + + + public function getSkippedHorizontalWhiteSpaceIfAny(): string + { + if ($this->index > 0 && $this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + return $this->tokens[$this->index - 1][Lexer::VALUE_OFFSET]; + } + + return ''; + } + + + /** @phpstan-impure */ + public function joinUntil(int ...$tokenType): string + { + $s = ''; + while (!in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, true)) { + $s .= $this->tokens[$this->index++][Lexer::VALUE_OFFSET]; + } + return $s; + } + + + public function next(): void + { + $this->index++; + + if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== Lexer::TOKEN_HORIZONTAL_WS) { + return; + } + + $this->index++; + } + + /** @phpstan-impure */ + public function forwardToTheEnd(): void + { + $lastToken = count($this->tokens) - 1; + $this->index = $lastToken; + } + + + public function pushSavePoint(): void + { + $this->savePoints[] = $this->index; + } + + + public function dropSavePoint(): void + { + array_pop($this->savePoints); + } + + + public function rollback(): void + { + $index = array_pop($this->savePoints); + assert($index !== null); + $this->index = $index; + } + + + /** + * @throws ParserException + */ + private function throwError(int $expectedTokenType, ?string $expectedTokenValue = null): void + { + throw new ParserException( + $this->currentTokenValue(), + $this->currentTokenType(), + $this->currentTokenOffset(), + $expectedTokenType, + $expectedTokenValue, + $this->currentTokenLine() + ); + } + + /** + * Check whether the position is directly preceded by a certain token type. + * + * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped + */ + public function hasTokenImmediatelyBefore(int $pos, int $expectedTokenType): bool + { + $tokens = $this->tokens; + $pos--; + for (; $pos >= 0; $pos--) { + $token = $tokens[$pos]; + $type = $token[Lexer::TYPE_OFFSET]; + if ($type === $expectedTokenType) { + return true; + } + if (!in_array($type, [ + Lexer::TOKEN_HORIZONTAL_WS, + Lexer::TOKEN_PHPDOC_EOL, + ], true)) { + break; + } + } + return false; + } + + /** + * Check whether the position is directly followed by a certain token type. + * + * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped + */ + public function hasTokenImmediatelyAfter(int $pos, int $expectedTokenType): bool + { + $tokens = $this->tokens; + $pos++; + for ($c = count($tokens); $pos < $c; $pos++) { + $token = $tokens[$pos]; + $type = $token[Lexer::TYPE_OFFSET]; + if ($type === $expectedTokenType) { + return true; + } + if (!in_array($type, [ + Lexer::TOKEN_HORIZONTAL_WS, + Lexer::TOKEN_PHPDOC_EOL, + ], true)) { + break; + } + } + + return false; + } + + /** + * Whether the given position is immediately surrounded by parenthesis. + */ + public function hasParentheses(int $startPos, int $endPos): bool + { + return $this->hasTokenImmediatelyBefore($startPos, Lexer::TOKEN_OPEN_PARENTHESES) + && $this->hasTokenImmediatelyAfter($endPos, Lexer::TOKEN_CLOSE_PARENTHESES); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php b/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php new file mode 100644 index 00000000..4b429809 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php @@ -0,0 +1,900 @@ +constExprParser = $constExprParser; + $this->quoteAwareConstExprString = $quoteAwareConstExprString; + $this->useLinesAttributes = $usedAttributes['lines'] ?? false; + $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; + } + + /** @phpstan-impure */ + public function parse(TokenIterator $tokens): Ast\Type\TypeNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { + $type = $this->parseNullable($tokens); + + } else { + $type = $this->parseAtomic($tokens); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) { + $type = $this->parseUnion($tokens, $type); + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) { + $type = $this->parseIntersection($tokens, $type); + } + } + + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + /** + * @internal + * @template T of Ast\Node + * @param T $type + * @return T + */ + public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node + { + $endLine = $tokens->currentTokenLine(); + $endIndex = $tokens->currentTokenIndex(); + + if ($this->useLinesAttributes) { + $type->setAttribute(Ast\Attribute::START_LINE, $startLine); + $type->setAttribute(Ast\Attribute::END_LINE, $endLine); + } + + if ($this->useIndexAttributes) { + $tokensArray = $tokens->getTokens(); + $endIndex--; + if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) { + $endIndex--; + } + + $type->setAttribute(Ast\Attribute::START_INDEX, $startIndex); + $type->setAttribute(Ast\Attribute::END_INDEX, $endIndex); + } + + return $type; + } + + /** @phpstan-impure */ + private function subParse(TokenIterator $tokens): Ast\Type\TypeNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { + $type = $this->parseNullable($tokens); + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) { + $type = $this->parseConditionalForParameter($tokens, $tokens->currentTokenValue()); + + } else { + $type = $this->parseAtomic($tokens); + + if ($tokens->isCurrentTokenValue('is')) { + $type = $this->parseConditional($tokens, $type); + } else { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) { + $type = $this->subParseUnion($tokens, $type); + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) { + $type = $this->subParseIntersection($tokens, $type); + } + } + } + + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + + /** @phpstan-impure */ + private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $type = $this->subParse($tokens); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); + } + + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) { + $type = $this->enrichWithAttributes($tokens, new Ast\Type\ThisTypeNode(), $startLine, $startIndex); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); + } + + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + $currentTokenValue = $tokens->currentTokenValue(); + $tokens->pushSavePoint(); // because of ConstFetchNode + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { + $type = $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex); + + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { + $tokens->dropSavePoint(); // because of ConstFetchNode + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { + $tokens->pushSavePoint(); + + $isHtml = $this->isHtml($tokens); + $tokens->rollback(); + if ($isHtml) { + return $type; + } + + $type = $this->parseGeneric($tokens, $type); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); + } + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { + $type = $this->tryParseCallable($tokens, $type); + + } 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()) { + if ($type->name === 'object') { + $type = $this->parseObjectShape($tokens); + } else { + $type = $this->parseArrayShape($tokens, $type, $type->name); + } + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess( + $tokens, + $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex) + ); + } + } + + return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } else { + $tokens->rollback(); // because of ConstFetchNode + } + } else { + $tokens->dropSavePoint(); // because of ConstFetchNode + } + + $exception = new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() + ); + + if ($this->constExprParser === null) { + throw $exception; + } + + try { + $constExpr = $this->constExprParser->parse($tokens, true); + if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { + throw $exception; + } + + return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex); + } catch (LogicException $e) { + throw $exception; + } + } + + + /** @phpstan-impure */ + private function parseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode + { + $types = [$type]; + + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) { + $types[] = $this->parseAtomic($tokens); + } + + return new Ast\Type\UnionTypeNode($types); + } + + + /** @phpstan-impure */ + private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode + { + $types = [$type]; + + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $types[] = $this->parseAtomic($tokens); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + } + + return new Ast\Type\UnionTypeNode($types); + } + + + /** @phpstan-impure */ + private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode + { + $types = [$type]; + + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) { + $types[] = $this->parseAtomic($tokens); + } + + return new Ast\Type\IntersectionTypeNode($types); + } + + + /** @phpstan-impure */ + private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode + { + $types = [$type]; + + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $types[] = $this->parseAtomic($tokens); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + } + + return new Ast\Type\IntersectionTypeNode($types); + } + + + /** @phpstan-impure */ + private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subjectType): Ast\Type\TypeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + + $negated = false; + if ($tokens->isCurrentTokenValue('not')) { + $negated = true; + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + } + + $targetType = $this->parse($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $ifType = $this->parse($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_COLON); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $elseType = $this->subParse($tokens); + + return new Ast\Type\ConditionalTypeNode($subjectType, $targetType, $ifType, $elseType, $negated); + } + + /** @phpstan-impure */ + private function parseConditionalForParameter(TokenIterator $tokens, string $parameterName): Ast\Type\TypeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); + $tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'is'); + + $negated = false; + if ($tokens->isCurrentTokenValue('not')) { + $negated = true; + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + } + + $targetType = $this->parse($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $ifType = $this->parse($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_COLON); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $elseType = $this->subParse($tokens); + + return new Ast\Type\ConditionalTypeForParameterNode($parameterName, $targetType, $ifType, $elseType, $negated); + } + + + /** @phpstan-impure */ + private function parseNullable(TokenIterator $tokens): Ast\Type\TypeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); + + $type = $this->parseAtomic($tokens); + + return new Ast\Type\NullableTypeNode($type); + } + + /** @phpstan-impure */ + public function isHtml(TokenIterator $tokens): bool + { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET); + + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { + return false; + } + + $htmlTagName = $tokens->currentTokenValue(); + + $tokens->next(); + + if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) { + return false; + } + + while (!$tokens->isCurrentTokenType(Lexer::TOKEN_END)) { + if ( + $tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET) + && strpos($tokens->currentTokenValue(), '/' . $htmlTagName . '>') !== false + ) { + return true; + } + + $tokens->next(); + } + + return false; + } + + /** @phpstan-impure */ + public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType): Ast\Type\GenericTypeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $genericTypes = []; + $variances = []; + + [$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) { + // trailing comma case + $type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances); + $startLine = $baseType->getAttribute(Ast\Attribute::START_LINE); + $startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX); + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + return $type; + } + [$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + } + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET); + + $type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances); + $startLine = $baseType->getAttribute(Ast\Attribute::START_LINE); + $startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX); + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); + } + + return $type; + } + + + /** + * @phpstan-impure + * @return array{Ast\Type\TypeNode, Ast\Type\GenericTypeNode::VARIANCE_*} + */ + public function parseGenericTypeArgument(TokenIterator $tokens): array + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) { + return [ + $this->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('mixed'), $startLine, $startIndex), + Ast\Type\GenericTypeNode::VARIANCE_BIVARIANT, + ]; + } + + if ($tokens->tryConsumeTokenValue('contravariant')) { + $variance = Ast\Type\GenericTypeNode::VARIANCE_CONTRAVARIANT; + } elseif ($tokens->tryConsumeTokenValue('covariant')) { + $variance = Ast\Type\GenericTypeNode::VARIANCE_COVARIANT; + } else { + $variance = Ast\Type\GenericTypeNode::VARIANCE_INVARIANT; + } + + $type = $this->parse($tokens); + return [$type, $variance]; + } + + + /** @phpstan-impure */ + private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier): Ast\Type\TypeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + $parameters = []; + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { + $parameters[] = $this->parseCallableParameter($tokens); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { + break; + } + $parameters[] = $this->parseCallableParameter($tokens); + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + } + } + + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); + $tokens->consumeTokenType(Lexer::TOKEN_COLON); + + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $returnType = $this->enrichWithAttributes($tokens, $this->parseCallableReturnType($tokens), $startLine, $startIndex); + + return new Ast\Type\CallableTypeNode($identifier, $parameters, $returnType); + } + + + /** @phpstan-impure */ + private function parseCallableParameter(TokenIterator $tokens): Ast\Type\CallableTypeParameterNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + $type = $this->parse($tokens); + $isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE); + $isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) { + $parameterName = $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_VARIABLE); + + } else { + $parameterName = ''; + } + + $isOptional = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); + return $this->enrichWithAttributes( + $tokens, + new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional), + $startLine, + $startIndex + ); + } + + + /** @phpstan-impure */ + private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) { + return $this->parseNullable($tokens); + + } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { + $type = $this->parse($tokens); + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); + } + + return $type; + } elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) { + $type = new Ast\Type\ThisTypeNode(); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } + + return $type; + } else { + $currentTokenValue = $tokens->currentTokenValue(); + $tokens->pushSavePoint(); // because of ConstFetchNode + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) { + $type = new Ast\Type\IdentifierTypeNode($currentTokenValue); + + if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) { + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) { + $type = $this->parseGeneric( + $tokens, + $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ) + ); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } + + } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + + } elseif (in_array($type->name, ['array', 'list', 'object'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) { + if ($type->name === 'object') { + $type = $this->parseObjectShape($tokens); + } else { + $type = $this->parseArrayShape($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ), $type->name); + } + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } + } + + return $type; + } else { + $tokens->rollback(); // because of ConstFetchNode + } + } else { + $tokens->dropSavePoint(); // because of ConstFetchNode + } + } + + $exception = new ParserException( + $tokens->currentTokenValue(), + $tokens->currentTokenType(), + $tokens->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER, + null, + $tokens->currentTokenLine() + ); + + if ($this->constExprParser === null) { + throw $exception; + } + + try { + $constExpr = $this->constExprParser->parse($tokens, true); + if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { + throw $exception; + } + + $type = new Ast\Type\ConstTypeNode($constExpr); + if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + )); + } + + return $type; + } catch (LogicException $e) { + throw $exception; + } + } + + + /** @phpstan-impure */ + private function tryParseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier): Ast\Type\TypeNode + { + try { + $tokens->pushSavePoint(); + $type = $this->parseCallable($tokens, $identifier); + $tokens->dropSavePoint(); + + } catch (ParserException $e) { + $tokens->rollback(); + $type = $identifier; + } + + return $type; + } + + + /** @phpstan-impure */ + private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\TypeNode + { + $startLine = $type->getAttribute(Ast\Attribute::START_LINE); + $startIndex = $type->getAttribute(Ast\Attribute::START_INDEX); + try { + while ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { + $tokens->pushSavePoint(); + + $canBeOffsetAccessType = !$tokens->isPrecededByHorizontalWhitespace(); + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET); + + if ($canBeOffsetAccessType && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET)) { + $offset = $this->parse($tokens); + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET); + $tokens->dropSavePoint(); + $type = new Ast\Type\OffsetAccessTypeNode($type, $offset); + + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ); + } + } else { + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET); + $tokens->dropSavePoint(); + $type = new Ast\Type\ArrayTypeNode($type); + + if ($startLine !== null && $startIndex !== null) { + $type = $this->enrichWithAttributes( + $tokens, + $type, + $startLine, + $startIndex + ); + } + } + } + + } catch (ParserException $e) { + $tokens->rollback(); + } + + return $type; + } + + + /** + * @phpstan-impure + * @param Ast\Type\ArrayShapeNode::KIND_* $kind + */ + private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type, string $kind): Ast\Type\ArrayShapeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET); + + $items = []; + $sealed = true; + + do { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { + return new Ast\Type\ArrayShapeNode($items, true, $kind); + } + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) { + $sealed = false; + $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA); + break; + } + + $items[] = $this->parseArrayShapeItem($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); + + return new Ast\Type\ArrayShapeNode($items, $sealed, $kind); + } + + + /** @phpstan-impure */ + private function parseArrayShapeItem(TokenIterator $tokens): Ast\Type\ArrayShapeItemNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + 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 + ); + } catch (ParserException $e) { + $tokens->rollback(); + $value = $this->parse($tokens); + + return $this->enrichWithAttributes( + $tokens, + new Ast\Type\ArrayShapeItemNode(null, false, $value), + $startLine, + $startIndex + ); + } + } + + /** + * @phpstan-impure + * @return Ast\ConstExpr\ConstExprIntegerNode|Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode + */ + private function parseArrayShapeKey(TokenIterator $tokens) + { + $startIndex = $tokens->currentTokenIndex(); + $startLine = $tokens->currentTokenLine(); + + if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) { + $key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue())); + $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(), "'")); + } + $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(), '"')); + } + + $tokens->next(); + + } else { + $key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + } + + return $this->enrichWithAttributes( + $tokens, + $key, + $startLine, + $startIndex + ); + } + + /** + * @phpstan-impure + */ + private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNode + { + $tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET); + + $items = []; + + do { + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + + if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { + return new Ast\Type\ObjectShapeNode($items); + } + + $items[] = $this->parseObjectShapeItem($tokens); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); + + $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); + $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); + + return new Ast\Type\ObjectShapeNode($items); + } + + /** @phpstan-impure */ + private function parseObjectShapeItem(TokenIterator $tokens): Ast\Type\ObjectShapeItemNode + { + $startLine = $tokens->currentTokenLine(); + $startIndex = $tokens->currentTokenIndex(); + + $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); + } + + /** + * @phpstan-impure + * @return Ast\ConstExpr\ConstExprStringNode|Ast\Type\IdentifierTypeNode + */ + private function parseObjectShapeKey(TokenIterator $tokens) + { + $startLine = $tokens->currentTokenLine(); + $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(), "'")); + } + $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(), '"')); + } + $tokens->next(); + + } else { + $key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + } + + return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex); + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php b/vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php new file mode 100644 index 00000000..2684dfc7 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php @@ -0,0 +1,44 @@ +type = $type; + $this->old = $old; + $this->new = $new; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php b/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php new file mode 100644 index 00000000..ab10be59 --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php @@ -0,0 +1,196 @@ +isEqual = $isEqual; + } + + /** + * Calculate diff (edit script) from $old to $new. + * + * @param T[] $old Original array + * @param T[] $new New array + * + * @return DiffElem[] Diff (edit script) + */ + public function diff(array $old, array $new): array + { + [$trace, $x, $y] = $this->calculateTrace($old, $new); + return $this->extractDiff($trace, $x, $y, $old, $new); + } + + /** + * Calculate diff, including "replace" operations. + * + * If a sequence of remove operations is followed by the same number of add operations, these + * will be coalesced into replace operations. + * + * @param T[] $old Original array + * @param T[] $new New array + * + * @return DiffElem[] Diff (edit script), including replace operations + */ + public function diffWithReplacements(array $old, array $new): array + { + return $this->coalesceReplacements($this->diff($old, $new)); + } + + /** + * @param T[] $old + * @param T[] $new + * @return array{array>, int, int} + */ + private function calculateTrace(array $old, array $new): array + { + $n = count($old); + $m = count($new); + $max = $n + $m; + $v = [1 => 0]; + $trace = []; + for ($d = 0; $d <= $max; $d++) { + $trace[] = $v; + for ($k = -$d; $k <= $d; $k += 2) { + if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) { + $x = $v[$k + 1]; + } else { + $x = $v[$k - 1] + 1; + } + + $y = $x - $k; + while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) { + $x++; + $y++; + } + + $v[$k] = $x; + if ($x >= $n && $y >= $m) { + return [$trace, $x, $y]; + } + } + } + throw new Exception('Should not happen'); + } + + /** + * @param array> $trace + * @param T[] $old + * @param T[] $new + * @return DiffElem[] + */ + private function extractDiff(array $trace, int $x, int $y, array $old, array $new): array + { + $result = []; + for ($d = count($trace) - 1; $d >= 0; $d--) { + $v = $trace[$d]; + $k = $x - $y; + + if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) { + $prevK = $k + 1; + } else { + $prevK = $k - 1; + } + + $prevX = $v[$prevK]; + $prevY = $prevX - $prevK; + + while ($x > $prevX && $y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]); + $x--; + $y--; + } + + if ($d === 0) { + break; + } + + while ($x > $prevX) { + $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null); + $x--; + } + + while ($y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]); + $y--; + } + } + return array_reverse($result); + } + + /** + * Coalesce equal-length sequences of remove+add into a replace operation. + * + * @param DiffElem[] $diff + * @return DiffElem[] + */ + private function coalesceReplacements(array $diff): array + { + $newDiff = []; + $c = count($diff); + for ($i = 0; $i < $c; $i++) { + $diffType = $diff[$i]->type; + if ($diffType !== DiffElem::TYPE_REMOVE) { + $newDiff[] = $diff[$i]; + continue; + } + + $j = $i; + while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { + $j++; + } + + $k = $j; + while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { + $k++; + } + + if ($j - $i === $k - $j) { + $len = $j - $i; + for ($n = 0; $n < $len; $n++) { + $newDiff[] = new DiffElem( + DiffElem::TYPE_REPLACE, + $diff[$i + $n]->old, + $diff[$j + $n]->new + ); + } + } else { + for (; $i < $k; $i++) { + $newDiff[] = $diff[$i]; + } + } + $i = $k - 1; + } + return $newDiff; + } + +} diff --git a/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php b/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php new file mode 100644 index 00000000..b65d83aa --- /dev/null +++ b/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php @@ -0,0 +1,803 @@ + */ + private $differ; + + /** + * Map From "{$class}->{$subNode}" to string that should be inserted + * between elements of this list subnode + * + * @var array + */ + private $listInsertionMap = [ + PhpDocNode::class . '->children' => "\n * ", + UnionTypeNode::class . '->types' => '|', + IntersectionTypeNode::class . '->types' => '&', + ArrayShapeNode::class . '->items' => ', ', + ObjectShapeNode::class . '->items' => ', ', + CallableTypeNode::class . '->parameters' => ', ', + GenericTypeNode::class . '->genericTypes' => ', ', + ConstExprArrayNode::class . '->items' => ', ', + MethodTagValueNode::class . '->parameters' => ', ', + ]; + + /** + * [$find, $extraLeft, $extraRight] + * + * @var array + */ + private $emptyListInsertionMap = [ + CallableTypeNode::class . '->parameters' => ['(', '', ''], + ArrayShapeNode::class . '->items' => ['{', '', ''], + ObjectShapeNode::class . '->items' => ['{', '', ''], + ]; + + /** @var array>> */ + private $parenthesesMap = [ + CallableTypeNode::class . '->returnType' => [ + CallableTypeNode::class, + UnionTypeNode::class, + IntersectionTypeNode::class, + ], + ArrayTypeNode::class . '->type' => [ + CallableTypeNode::class, + UnionTypeNode::class, + IntersectionTypeNode::class, + ConstTypeNode::class, + NullableTypeNode::class, + ], + OffsetAccessTypeNode::class . '->type' => [ + CallableTypeNode::class, + UnionTypeNode::class, + IntersectionTypeNode::class, + ConstTypeNode::class, + NullableTypeNode::class, + ], + ]; + + /** @var array>> */ + private $parenthesesListMap = [ + IntersectionTypeNode::class . '->types' => [ + IntersectionTypeNode::class, + UnionTypeNode::class, + NullableTypeNode::class, + ], + UnionTypeNode::class . '->types' => [ + IntersectionTypeNode::class, + UnionTypeNode::class, + NullableTypeNode::class, + ], + ]; + + public function printFormatPreserving(PhpDocNode $node, PhpDocNode $originalNode, TokenIterator $originalTokens): string + { + $this->differ = new Differ(static function ($a, $b) { + if ($a instanceof Node && $b instanceof Node) { + return $a === $b->getAttribute(Attribute::ORIGINAL_NODE); + } + + return false; + }); + + $tokenIndex = 0; + $result = $this->printArrayFormatPreserving( + $node->children, + $originalNode->children, + $originalTokens, + $tokenIndex, + PhpDocNode::class, + 'children' + ); + if ($result !== null) { + return $result . $originalTokens->getContentBetween($tokenIndex, $originalTokens->getTokenCount()); + } + + return $this->print($node); + } + + public function print(Node $node): string + { + if ($node instanceof PhpDocNode) { + return "/**\n *" . implode("\n *", array_map( + function (PhpDocChildNode $child): string { + $s = $this->print($child); + return $s === '' ? '' : ' ' . $s; + }, + $node->children + )) . "\n */"; + } + if ($node instanceof PhpDocTextNode) { + return $node->text; + } + if ($node instanceof PhpDocTagNode) { + return trim(sprintf('%s %s', $node->name, $this->print($node->value))); + } + if ($node instanceof PhpDocTagValueNode) { + return $this->printTagValue($node); + } + if ($node instanceof TypeNode) { + return $this->printType($node); + } + if ($node instanceof ConstExprNode) { + return $this->printConstExpr($node); + } + if ($node instanceof MethodTagValueParameterNode) { + $type = $node->type !== null ? $this->print($node->type) . ' ' : ''; + $isReference = $node->isReference ? '&' : ''; + $isVariadic = $node->isVariadic ? '...' : ''; + $default = $node->defaultValue !== null ? ' = ' . $this->print($node->defaultValue) : ''; + return "{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}"; + } + if ($node instanceof CallableTypeParameterNode) { + $type = $this->print($node->type) . ' '; + $isReference = $node->isReference ? '&' : ''; + $isVariadic = $node->isVariadic ? '...' : ''; + $isOptional = $node->isOptional ? '=' : ''; + return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional; + } + + throw new LogicException(sprintf('Unknown node type %s', get_class($node))); + } + + private function printTagValue(PhpDocTagValueNode $node): string + { + // only nodes that contain another node are handled here + // the rest falls back on (string) $node + + if ($node instanceof AssertTagMethodValueNode) { + $isNegated = $node->isNegated ? '!' : ''; + $isEquality = $node->isEquality ? '=' : ''; + $type = $this->printType($node->type); + return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->method}() {$node->description}"); + } + if ($node instanceof AssertTagPropertyValueNode) { + $isNegated = $node->isNegated ? '!' : ''; + $isEquality = $node->isEquality ? '=' : ''; + $type = $this->printType($node->type); + return trim("{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->property} {$node->description}"); + } + if ($node instanceof AssertTagValueNode) { + $isNegated = $node->isNegated ? '!' : ''; + $isEquality = $node->isEquality ? '=' : ''; + $type = $this->printType($node->type); + return trim("{$isNegated}{$isEquality}{$type} {$node->parameter} {$node->description}"); + } + if ($node instanceof ExtendsTagValueNode || $node instanceof ImplementsTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + 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)); + $description = $node->description !== '' ? " {$node->description}" : ''; + $templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateTag): string { + return $this->print($templateTag); + }, $node->templateTypes)) . '>' : ''; + return "{$static}{$returnType}{$node->methodName}{$templateTypes}({$parameters}){$description}"; + } + if ($node instanceof MixinTagValueNode) { + $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}"); + } + if ($node instanceof ParamTagValueNode) { + $reference = $node->isReference ? '&' : ''; + $variadic = $node->isVariadic ? '...' : ''; + $type = $this->printType($node->type); + return trim("{$type} {$reference}{$variadic}{$node->parameterName} {$node->description}"); + } + if ($node instanceof PropertyTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->propertyName} {$node->description}"); + } + if ($node instanceof ReturnTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof SelfOutTagValueNode) { + $type = $this->printType($node->type); + return trim($type . ' ' . $node->description); + } + if ($node instanceof TemplateTagValueNode) { + $bound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : ''; + $default = $node->default !== null ? ' = ' . $this->printType($node->default) : ''; + return trim("{$node->name}{$bound}{$default} {$node->description}"); + } + if ($node instanceof ThrowsTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof TypeAliasImportTagValueNode) { + return trim( + "{$node->importedAlias} from " . $this->printType($node->importedFrom) + . ($node->importedAs !== null ? " as {$node->importedAs}" : '') + ); + } + if ($node instanceof TypeAliasTagValueNode) { + $type = $this->printType($node->type); + return trim("{$node->alias} {$type}"); + } + if ($node instanceof UsesTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} {$node->description}"); + } + if ($node instanceof VarTagValueNode) { + $type = $this->printType($node->type); + return trim("{$type} " . trim("{$node->variableName} {$node->description}")); + } + + return (string) $node; + } + + private function printType(TypeNode $node): string + { + if ($node instanceof ArrayShapeNode) { + $items = array_map(function (ArrayShapeItemNode $item): string { + return $this->printType($item); + }, $node->items); + + if (! $node->sealed) { + $items[] = '...'; + } + + 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) . '[]'; + } + if ($node instanceof CallableTypeNode) { + if ($node->returnType instanceof CallableTypeNode || $node->returnType instanceof UnionTypeNode || $node->returnType instanceof IntersectionTypeNode) { + $returnType = $this->wrapInParentheses($node->returnType); + } else { + $returnType = $this->printType($node->returnType); + } + $parameters = implode(', ', array_map(function (CallableTypeParameterNode $parameterNode): string { + return $this->print($parameterNode); + }, $node->parameters)); + return "{$node->identifier}({$parameters}): {$returnType}"; + } + if ($node instanceof ConditionalTypeForParameterNode) { + return sprintf( + '(%s %s %s ? %s : %s)', + $node->parameterName, + $node->negated ? 'is not' : 'is', + $this->printType($node->targetType), + $this->printType($node->if), + $this->printType($node->else) + ); + } + if ($node instanceof ConditionalTypeNode) { + return sprintf( + '(%s %s %s ? %s : %s)', + $this->printType($node->subjectType), + $node->negated ? 'is not' : 'is', + $this->printType($node->targetType), + $this->printType($node->if), + $this->printType($node->else) + ); + } + if ($node instanceof ConstTypeNode) { + return $this->printConstExpr($node->constExpr); + } + if ($node instanceof GenericTypeNode) { + $genericTypes = []; + + foreach ($node->genericTypes as $index => $type) { + $variance = $node->variances[$index] ?? GenericTypeNode::VARIANCE_INVARIANT; + if ($variance === GenericTypeNode::VARIANCE_INVARIANT) { + $genericTypes[] = $this->printType($type); + } elseif ($variance === GenericTypeNode::VARIANCE_BIVARIANT) { + $genericTypes[] = '*'; + } else { + $genericTypes[] = sprintf('%s %s', $variance, $this->print($type)); + } + } + + return $node->type . '<' . implode(', ', $genericTypes) . '>'; + } + if ($node instanceof IdentifierTypeNode) { + return $node->name; + } + if ($node instanceof IntersectionTypeNode || $node instanceof UnionTypeNode) { + $items = []; + foreach ($node->types as $type) { + if ( + $type instanceof IntersectionTypeNode + || $type instanceof UnionTypeNode + || $type instanceof NullableTypeNode + ) { + $items[] = $this->wrapInParentheses($type); + continue; + } + + $items[] = $this->printType($type); + } + + return implode($node instanceof IntersectionTypeNode ? '&' : '|', $items); + } + if ($node instanceof InvalidTypeNode) { + return (string) $node; + } + if ($node instanceof NullableTypeNode) { + if ($node->type instanceof IntersectionTypeNode || $node->type instanceof UnionTypeNode) { + return '?(' . $this->printType($node->type) . ')'; + } + + return '?' . $this->printType($node->type); + } + if ($node instanceof ObjectShapeNode) { + $items = array_map(function (ObjectShapeItemNode $item): string { + return $this->printType($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) . ']'; + } + if ($node instanceof ThisTypeNode) { + return (string) $node; + } + + throw new LogicException(sprintf('Unknown node type %s', get_class($node))); + } + + private function wrapInParentheses(TypeNode $node): string + { + return '(' . $this->printType($node) . ')'; + } + + private function printOffsetAccessType(TypeNode $type): string + { + if ( + $type instanceof CallableTypeNode + || $type instanceof UnionTypeNode + || $type instanceof IntersectionTypeNode + || $type instanceof ConstTypeNode + || $type instanceof NullableTypeNode + ) { + return $this->wrapInParentheses($type); + } + + return $this->printType($type); + } + + private function printConstExpr(ConstExprNode $node): string + { + // this is fine - ConstExprNode classes do not contain nodes that need smart printer logic + return (string) $node; + } + + /** + * @param Node[] $nodes + * @param Node[] $originalNodes + */ + private function printArrayFormatPreserving(array $nodes, array $originalNodes, TokenIterator $originalTokens, int &$tokenIndex, string $parentNodeClass, string $subNodeName): ?string + { + $diff = $this->differ->diffWithReplacements($originalNodes, $nodes); + $mapKey = $parentNodeClass . '->' . $subNodeName; + $insertStr = $this->listInsertionMap[$mapKey] ?? null; + $result = ''; + $beforeFirstKeepOrReplace = true; + $delayedAdd = []; + + $insertNewline = false; + [$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens); + + if ($insertStr === "\n * ") { + $insertStr = sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } + + foreach ($diff as $i => $diffElem) { + $diffType = $diffElem->type; + $newNode = $diffElem->new; + $originalNode = $diffElem->old; + if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { + $beforeFirstKeepOrReplace = false; + if (!$newNode instanceof Node || !$originalNode instanceof Node) { + return null; + } + $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); + $itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX); + if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) { + throw new LogicException(); + } + + $result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos); + + if (count($delayedAdd) > 0) { + foreach ($delayedAdd as $delayedAddNode) { + $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) + && in_array(get_class($delayedAddNode), $this->parenthesesListMap[$mapKey], true); + if ($parenthesesNeeded) { + $result .= '('; + } + $result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens); + if ($parenthesesNeeded) { + $result .= ')'; + } + + if ($insertNewline) { + $result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } else { + $result .= $insertStr; + } + } + + $delayedAdd = []; + } + + $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) + && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true) + && !in_array(get_class($originalNode), $this->parenthesesListMap[$mapKey], true); + $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos); + if ($addParentheses) { + $result .= '('; + } + + $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); + if ($addParentheses) { + $result .= ')'; + } + $tokenIndex = $itemEndPos + 1; + + } elseif ($diffType === DiffElem::TYPE_ADD) { + if ($insertStr === null) { + return null; + } + if (!$newNode instanceof Node) { + return null; + } + + if ($insertStr === ', ' && $isMultiline) { + $insertStr = ','; + $insertNewline = true; + } + + if ($beforeFirstKeepOrReplace) { + // Will be inserted at the next "replace" or "keep" element + $delayedAdd[] = $newNode; + continue; + } + + $itemEndPos = $tokenIndex - 1; + if ($insertNewline) { + $result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } else { + $result .= $insertStr; + } + + $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) + && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true); + if ($parenthesesNeeded) { + $result .= '('; + } + + $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); + if ($parenthesesNeeded) { + $result .= ')'; + } + + $tokenIndex = $itemEndPos + 1; + + } elseif ($diffType === DiffElem::TYPE_REMOVE) { + if (!$originalNode instanceof Node) { + return null; + } + + $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); + $itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX); + if ($itemStartPos < 0 || $itemEndPos < 0) { + throw new LogicException(); + } + + if ($i === 0) { + // If we're removing from the start, keep the tokens before the node and drop those after it, + // instead of the other way around. + $originalTokensArray = $originalTokens->getTokens(); + for ($j = $tokenIndex; $j < $itemStartPos; $j++) { + if ($originalTokensArray[$j][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) { + break; + } + $result .= $originalTokensArray[$j][Lexer::VALUE_OFFSET]; + } + } + + $tokenIndex = $itemEndPos + 1; + } + } + + if (count($delayedAdd) > 0) { + if (!isset($this->emptyListInsertionMap[$mapKey])) { + return null; + } + + [$findToken, $extraLeft, $extraRight] = $this->emptyListInsertionMap[$mapKey]; + if ($findToken !== null) { + $originalTokensArray = $originalTokens->getTokens(); + for (; $tokenIndex < count($originalTokensArray); $tokenIndex++) { + $result .= $originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET]; + if ($originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET] !== $findToken) { + continue; + } + + $tokenIndex++; + break; + } + } + $first = true; + $result .= $extraLeft; + foreach ($delayedAdd as $delayedAddNode) { + if (!$first) { + $result .= $insertStr; + if ($insertNewline) { + $result .= sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent); + } + } + + $result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens); + $first = false; + } + $result .= $extraRight; + } + + return $result; + } + + /** + * @param Node[] $nodes + * @return array{bool, string, string} + */ + private function isMultiline(int $initialIndex, array $nodes, TokenIterator $originalTokens): array + { + $isMultiline = count($nodes) > 1; + $pos = $initialIndex; + $allText = ''; + /** @var Node|null $node */ + foreach ($nodes as $node) { + if (!$node instanceof Node) { + continue; + } + + $endPos = $node->getAttribute(Attribute::END_INDEX) + 1; + $text = $originalTokens->getContentBetween($pos, $endPos); + $allText .= $text; + if (strpos($text, "\n") === false) { + // We require that a newline is present between *every* item. If the formatting + // is inconsistent, with only some items having newlines, we don't consider it + // as multiline + $isMultiline = false; + } + $pos = $endPos; + } + + $c = preg_match_all('~\n(?[\\x09\\x20]*)\*(?\\x20*)~', $allText, $matches, PREG_SET_ORDER); + if ($c === 0) { + return [$isMultiline, '', '']; + } + + $before = ''; + $after = ''; + foreach ($matches as $match) { + if (strlen($match['before']) > strlen($before)) { + $before = $match['before']; + } + if (strlen($match['after']) <= strlen($after)) { + continue; + } + + $after = $match['after']; + } + + return [$isMultiline, $before, $after]; + } + + private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens): string + { + /** @var Node|null $originalNode */ + $originalNode = $node->getAttribute(Attribute::ORIGINAL_NODE); + if ($originalNode === null) { + return $this->print($node); + } + + $class = get_class($node); + if ($class !== get_class($originalNode)) { + throw new LogicException(); + } + + $startPos = $originalNode->getAttribute(Attribute::START_INDEX); + $endPos = $originalNode->getAttribute(Attribute::END_INDEX); + if ($startPos < 0 || $endPos < 0) { + throw new LogicException(); + } + + $result = ''; + $pos = $startPos; + $subNodeNames = array_keys(get_object_vars($node)); + foreach ($subNodeNames as $subNodeName) { + $subNode = $node->$subNodeName; + $origSubNode = $originalNode->$subNodeName; + + if ( + (!$subNode instanceof Node && $subNode !== null) + || (!$origSubNode instanceof Node && $origSubNode !== null) + ) { + if ($subNode === $origSubNode) { + // Unchanged, can reuse old code + continue; + } + + if (is_array($subNode) && is_array($origSubNode)) { + // Array subnode changed, we might be able to reconstruct it + $listResult = $this->printArrayFormatPreserving( + $subNode, + $origSubNode, + $originalTokens, + $pos, + $class, + $subNodeName + ); + + if ($listResult === null) { + return $this->print($node); + } + + $result .= $listResult; + continue; + } + + return $this->print($node); + } + + if ($origSubNode === null) { + if ($subNode === null) { + // Both null, nothing to do + continue; + } + + return $this->print($node); + } + + $subStartPos = $origSubNode->getAttribute(Attribute::START_INDEX); + $subEndPos = $origSubNode->getAttribute(Attribute::END_INDEX); + if ($subStartPos < 0 || $subEndPos < 0) { + throw new LogicException(); + } + + if ($subNode === null) { + return $this->print($node); + } + + $result .= $originalTokens->getContentBetween($pos, $subStartPos); + $mapKey = get_class($node) . '->' . $subNodeName; + $parenthesesNeeded = isset($this->parenthesesMap[$mapKey]) + && in_array(get_class($subNode), $this->parenthesesMap[$mapKey], true); + + if ($subNode->getAttribute(Attribute::ORIGINAL_NODE) !== null) { + $parenthesesNeeded = $parenthesesNeeded + && !in_array(get_class($subNode->getAttribute(Attribute::ORIGINAL_NODE)), $this->parenthesesMap[$mapKey], true); + } + + $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($subStartPos, $subEndPos); + if ($addParentheses) { + $result .= '('; + } + + $result .= $this->printNodeFormatPreserving($subNode, $originalTokens); + if ($addParentheses) { + $result .= ')'; + } + + $pos = $subEndPos + 1; + } + + return $result . $originalTokens->getContentBetween($pos, $endPos + 1); + } + +} diff --git a/vendor/phpstan/phpstan/bootstrap.php b/vendor/phpstan/phpstan/bootstrap.php index 204221a3..1537f3f1 100644 --- a/vendor/phpstan/phpstan/bootstrap.php +++ b/vendor/phpstan/phpstan/bootstrap.php @@ -23,7 +23,6 @@ final class PharAutoloader self::$composerAutoloader = require 'phar://' . __DIR__ . '/phpstan.phar/vendor/autoload.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/jetbrains/phpstorm-stubs/PhpStormStubsMap.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/async/src/functions_include.php'; - require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise-stream/src/functions_include.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise-timer/src/functions_include.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/react/promise/src/functions_include.php'; require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/ringcentral/psr7/src/functions_include.php'; diff --git a/vendor/phpstan/phpstan/composer.json b/vendor/phpstan/phpstan/composer.json index 55182f6c..07faa85b 100644 --- a/vendor/phpstan/phpstan/composer.json +++ b/vendor/phpstan/phpstan/composer.json @@ -15,5 +15,12 @@ ], "autoload": { "files": ["bootstrap.php"] + }, + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "forum": "https://github.com/phpstan/phpstan/discussions", + "source": "https://github.com/phpstan/phpstan-src", + "docs": "https://phpstan.org/user-guide/getting-started", + "security": "https://github.com/phpstan/phpstan/security/policy" } } diff --git a/vendor/phpstan/phpstan/phpstan.phar b/vendor/phpstan/phpstan/phpstan.phar index 74360dd9..3f043c71 100755 Binary files a/vendor/phpstan/phpstan/phpstan.phar and b/vendor/phpstan/phpstan/phpstan.phar differ diff --git a/vendor/phpstan/phpstan/phpstan.phar.asc b/vendor/phpstan/phpstan/phpstan.phar.asc index cdc7a12d..3c34229a 100644 --- a/vendor/phpstan/phpstan/phpstan.phar.asc +++ b/vendor/phpstan/phpstan/phpstan.phar.asc @@ -1,16 +1,16 @@ -----BEGIN PGP SIGNATURE----- -iQIzBAABCgAdFiEE0yaA1ZV9xxFr4pwUzxoQjQ565yAFAmQKD1cACgkQzxoQjQ56 -5yDePQ//ZtI/AKKhBlTvj6I6mw69TBuVi/7y+uU0CyrgKodCJlBCvprybXS2GItU -rh2rMrX75IGOx8tEBs/6Ec5BuPF5rIQZdPndsYzT+sH8hBCLCQ/SlgtE/bZ7CIjr -/WBkTjXd+T2lGmIe1e57rxNUiy+tgWlEa/mf963lY5Oy5zfuui6HEVzEofGtdq3c -l9FSx+9pVX4rCHKZzCy1lNuh3xdHEYS52mMCsYuuOo0GZ9e1cqFBj4VwF9WkLlr5 -oEvJanpJx32YcYOkhD1tE5N/3Gxtw1AZMSq4onJvts8YyqGA2q7uTDdRmW2yyiB7 -DgPFrfE2rNGCymU6n04hPhKyMIBk8nJB89qYtInIzbpm7+xPRrt6pKWFGIvAXeNx -qDHM3H+efvDadXl47z3aJLsgXxnefI6VJjXJF28mxEmwtm9Jt6tNvzEz+FHDgM11 -xat1m+oREXArPNA7cDTu5IIQY0BomKKc6H8X/X5OtKoVj0xoXbu/tfLVIJ8XYech -oAc+F0eA1k3vNxd5owM3ZaNqAFsGCA0dAgUWm2sNliZZZcnx0pWDvl/CG/Qetktz -15DvlfokTtCXPihy4tk1rYh/+EZfrwTJAMg4Xn3t9XlBapLUVH09EoRRi/0cVs9J -7x1FBChPFcvMSwrPo+mPzmjTfJ59QCt0BqYk7q/84KtcX85KQlg= -=3/5f +iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmRaZmcACgkQUcZzBf/C +5cAn/Q//fbWiR/qaSvlHpk73KH7iDfoHwNvRrHSQODZdMa4PGiEbL+SXsKnRxFDo +kEJZwgU5qi3WMflt7Ml3dYDlQDgoDerdaiySYFoBcv1NXDWKoF7+Egy1AHxpfNq+ +FMCkZNR2ulSaYUCofM4GkTNap4yVkPCy289ZU6yUmRnJxF+hh/CFfdVPAPbwh/a6 +UqV3R2ENJZSbtA1pzSTBpUPQGQ9qcsqngKyNyxk1hEd9opdMg2eSFvO1e1ZZm/Tk +Kgh5wCbsbSJuRPGO4vbiybTeO/qXPDlHV6oA5SHnjJ4H24phCsHdyJHHvLQmrUeR +BKHgnH1y/b5J9cgr9OgEQJK9TMHHd6dii9//Qp+0rUZIDZ4Ym2lDSA/Vn/D9GoV3 +zo4QYzW3TvE3QMdnLcX/ZtaLliPdDYIaYUXOiyaYwLFGVxSWZWOC5IN0G0bLJb39 +Ca/z839nkWdMqg68q/oHC2Nk/v/KZnKg1RlRjYhj53T6nr0JDEiaYMyETSOIFsVX +AcCQnLLwMndUAibJAyORDnTk+ipg0SecFoPvvhea1BtlTfhSDIlrT4OPKZ5nExzd +nR/zGbIH8lCvsBc+hq+Kgodtfs5nauwEOwlVUwet26xL1YKOd0jxz+Zp6tgk0wba +cMf5L9fm85j83DQYr7Ukaaj81kmMujRWDo/dRojKhUlJUrNnjXA= +=jTtX -----END PGP SIGNATURE----- diff --git a/vendor/phpunit/phpunit/ChangeLog-8.5.md b/vendor/phpunit/phpunit/ChangeLog-8.5.md deleted file mode 100644 index a65e6a61..00000000 --- a/vendor/phpunit/phpunit/ChangeLog-8.5.md +++ /dev/null @@ -1,304 +0,0 @@ -# Changes in PHPUnit 8.5 - -All notable changes of the PHPUnit 8.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. - -## [8.5.33] - 2023-02-27 - -### Fixed - -* [#5186](https://github.com/sebastianbergmann/phpunit/issues/5186): SBOM does not validate - -## [8.5.32] - 2023-01-26 - -### Fixed - -* [#5120](https://github.com/sebastianbergmann/phpunit/issues/5120): Test Runner incorrectly treats `--testsuite` and `--list-tests` as not combinable options - -## [8.5.31] - 2022-10-28 - -### Fixed - -* [#5076](https://github.com/sebastianbergmann/phpunit/issues/5076): Test Runner does not warn about conflicting options - -## [8.5.30] - 2022-09-25 - -### Changed - -* The configuration generator now asks for a cache directory - -### Fixed - -* [#4913](https://github.com/sebastianbergmann/phpunit/issues/4913): Failed `assert()` should show a backtrace -* [#4966](https://github.com/sebastianbergmann/phpunit/issues/4966): `TestCase::assertSame()` (and related exact comparisons) must compare `float` exactly - -## [8.5.29] - 2022-08-22 - -### Changed - -* [#5033](https://github.com/sebastianbergmann/phpunit/issues/5033): Do not depend on phpspec/prophecy - -## [8.5.28] - 2022-07-29 - -### Fixed - -* [#5015](https://github.com/sebastianbergmann/phpunit/pull/5015): Ukraine banner unreadable on black background -* [#5016](https://github.com/sebastianbergmann/phpunit/issues/5016): PHPUnit 8.5.27 does not work on PHP 7.2.0-7.2.18 and PHP 7.3.0-7.3.5 - -## [8.5.27] - 2022-06-19 - -### Fixed - -* [#4950](https://github.com/sebastianbergmann/phpunit/issues/4950): False error on `atMost()` invocation rule without call -* [#4962](https://github.com/sebastianbergmann/phpunit/issues/4962): Ukraine banner unreadable on white background - -## [8.5.26] - 2022-04-01 - -### Fixed - -* [#4938](https://github.com/sebastianbergmann/phpunit/issues/4938): Test Double code generator does not handle `void` return type declaration on `__clone()` methods - -## [8.5.25] - 2022-03-16 - -### Fixed - -* [#4934](https://github.com/sebastianbergmann/phpunit/issues/4934): Code Coverage does not work with PHPUnit 8.5.24 PHAR on PHP 7 - -## [8.5.24] - 2022-03-05 - #StandWithUkraine - -### Changed - -* [#4874](https://github.com/sebastianbergmann/phpunit/pull/4874): `PHP_FLOAT_EPSILON` is now used instead of hardcoded `0.0000000001` in `PHPUnit\Framework\Constraint\IsIdentical` - -### Fixed - -* When the HTML code coverage report's configured low upper bound is larger than the high lower bound then the default values are used instead - -## [8.5.23] - 2022-01-21 - -### Fixed - -* [#4799](https://github.com/sebastianbergmann/phpunit/pull/4799): Memory leaks in `PHPUnit\Framework\TestSuite` class -* [#4857](https://github.com/sebastianbergmann/phpunit/pull/4857): Result of `debug_backtrace()` is not used correctly - -## [8.5.22] - 2021-12-25 - -### Changed - -* [#4812](https://github.com/sebastianbergmann/phpunit/issues/4812): Do not enforce time limits when a debugging session through DBGp is active -* [#4835](https://github.com/sebastianbergmann/phpunit/issues/4835): Support for `$GLOBALS['_composer_autoload_path']` introduced in Composer 2.2 - -### Fixed - -* [#4840](https://github.com/sebastianbergmann/phpunit/pull/4840): TestDox prettifying for class names does not correctly handle diacritics -* [#4846](https://github.com/sebastianbergmann/phpunit/pull/4846): Composer proxy script is not ignored - -## [8.5.21] - 2021-09-25 - -### Changed - -* PHPUnit no longer converts PHP deprecations to exceptions by default (configure `convertDeprecationsToExceptions="true"` to enable this) -* The PHPUnit XML configuration file generator now configures `convertDeprecationsToExceptions="true"` - -### Fixed - -* [#4772](https://github.com/sebastianbergmann/phpunit/pull/4772): TestDox HTML report not displayed correctly when browser has custom colour settings - -## [8.5.20] - 2021-08-31 - -### Fixed - -* [#4751](https://github.com/sebastianbergmann/phpunit/issues/4751): Configuration validation fails when using brackets in glob pattern - -## [8.5.19] - 2021-07-31 - -### Fixed - -* [#4740](https://github.com/sebastianbergmann/phpunit/issues/4740): `phpunit.phar` does not work with PHP 8.1 - -## [8.5.18] - 2021-07-19 - -### Fixed - -* [#4720](https://github.com/sebastianbergmann/phpunit/issues/4720): PHPUnit does not verify its own PHP extension requirements - -## [8.5.17] - 2021-06-23 - -### Changed - -* PHPUnit now errors out on startup when `PHP_VERSION` contains a value that is not compatible with `version_compare()`, for instance `X.Y.Z-(to be removed in future macOS)` - -## [8.5.16] - 2021-06-05 - -### Changed - -* The test result cache (the storage for which is implemented in `PHPUnit\Runner\DefaultTestResultCache`) no longer uses PHP's `serialize()` and `unserialize()` functions for persistence. It now uses a versioned JSON format instead that is independent of PHP implementation details (see [#3581](https://github.com/sebastianbergmann/phpunit/issues/3581) and [#4662](https://github.com/sebastianbergmann/phpunit/pull/4662) for examples why this is a problem). When PHPUnit tries to load the test result cache from a file that does not exist, or from a file that does not contain data in JSON format, or from a file that contains data in a JSON format version other than the one used by the currently running PHPUnit version, then this is considered to be a "cache miss". An empty `DefaultTestResultCache` object is created in this case. This should also prevent PHPUnit from crashing when trying to load a test result cache file created by a different version of PHPUnit (see [#4580](https://github.com/sebastianbergmann/phpunit/issues/4580) for example). - -### Fixed - -* [#4663](https://github.com/sebastianbergmann/phpunit/issues/4663): `TestCase::expectError()` works on PHP 7.3, but not on PHP >= 7.4 -* [#4678](https://github.com/sebastianbergmann/phpunit/pull/4678): Stubbed methods with `iterable` return types should return empty array by default -* [#4692](https://github.com/sebastianbergmann/phpunit/issues/4692): Annotations in single-line doc-comments are not handled correctly -* [#4694](https://github.com/sebastianbergmann/phpunit/issues/4694): `TestCase::getMockFromWsdl()` does not work with PHP 8.1-dev - -## [8.5.15] - 2021-03-17 - -### Fixed - -* [#4591](https://github.com/sebastianbergmann/phpunit/issues/4591): TeamCity logger logs warnings as test failures - -## [8.5.14] - 2021-01-17 - -### Fixed - -* [#4535](https://github.com/sebastianbergmann/phpunit/issues/4535): `getMockFromWsdl()` does not handle methods that do not have parameters correctly -* [#4572](https://github.com/sebastianbergmann/phpunit/issues/4572): Schema validation does not work with `%xx` sequences in path to `phpunit.xsd` -* [#4575](https://github.com/sebastianbergmann/phpunit/issues/4575): PHPUnit 8.5 incompatibility with PHP 8.1 - -## [8.5.13] - 2020-12-01 - -### Fixed - -* Running tests in isolated processes did not work with PHP 8 on Windows - -## [8.5.12] - 2020-11-30 - -### Changed - -* Changed PHP version constraint in `composer.json` from `^7.2` to `>=7.2` to allow the installation of PHPUnit 8.5 on PHP 8. Please note that the code coverage functionality is not available for PHPUnit 8.5 on PHP 8. - -### Fixed - -* [#4529](https://github.com/sebastianbergmann/phpunit/issues/4529): Debug mode of Xdebug 2 is not disabled for PHPT tests - -## [8.5.11] - 2020-11-27 - -### Changed - -* Bumped required version of `phpunit/php-code-coverage` - -## [8.5.10] - 2020-11-27 - -### Added - -* Support for Xdebug 3 - -### Fixed - -* [#4516](https://github.com/sebastianbergmann/phpunit/issues/4516): `phpunit/phpunit-selenium` does not work with PHPUnit 8.5.9 - -## [8.5.9] - 2020-11-10 - -### Fixed - -* [#3965](https://github.com/sebastianbergmann/phpunit/issues/3965): Process Isolation throws exceptions when PHPDBG is used -* [#4470](https://github.com/sebastianbergmann/phpunit/pull/4470): Infinite recursion when `--static-backup --strict-global-state` is used - -## [8.5.8] - 2020-06-22 - -### Fixed - -* [#4312](https://github.com/sebastianbergmann/phpunit/issues/4312): Fix for [#4299](https://github.com/sebastianbergmann/phpunit/issues/4299) breaks backward compatibility - -## [8.5.7] - 2020-06-21 - -### Fixed - -* [#4299](https://github.com/sebastianbergmann/phpunit/issues/4299): "No tests executed" does not always result in exit code `1` -* [#4306](https://github.com/sebastianbergmann/phpunit/issues/4306): Exceptions during code coverage driver initialization are not handled correctly - -## [8.5.6] - 2020-06-15 - -### Fixed - -* [#4211](https://github.com/sebastianbergmann/phpunit/issues/4211): `phpdbg_*()` functions are scoped to `PHPUnit\phpdbg_*()` - -## [8.5.5] - 2020-05-22 - -### Fixed - -* [#4033](https://github.com/sebastianbergmann/phpunit/issues/4033): Unexpected behaviour when `$GLOBALS` is deleted - -## [8.5.4] - 2020-04-23 - -### Changed - -* Changed how `PHPUnit\TextUI\Command` passes warnings to `PHPUnit\TextUI\TestRunner` - -## [8.5.3] - 2020-03-31 - -### Fixed - -* [#4017](https://github.com/sebastianbergmann/phpunit/issues/4017): Do not suggest refactoring to something that is also deprecated -* [#4133](https://github.com/sebastianbergmann/phpunit/issues/4133): `expectExceptionMessageRegExp()` has been removed in PHPUnit 9 without a deprecation warning being given in PHPUnit 8 -* [#4139](https://github.com/sebastianbergmann/phpunit/issues/4139): Cannot double interfaces that declare a constructor with PHP 8 -* [#4144](https://github.com/sebastianbergmann/phpunit/issues/4144): Empty objects are converted to empty arrays in JSON comparison failure diff - -## [8.5.2] - 2020-01-08 - -### Removed - -* `eval-stdin.php` has been removed, it was not used anymore since PHPUnit 7.2.7 - -## [8.5.1] - 2019-12-25 - -### Changed - -* `eval-stdin.php` can now only be executed with `cli` and `phpdbg` - -### Fixed - -* [#3983](https://github.com/sebastianbergmann/phpunit/issues/3983): Deprecation warning given too eagerly - -## [8.5.0] - 2019-12-06 - -### Added - -* [#3911](https://github.com/sebastianbergmann/phpunit/issues/3911): Support combined use of `addMethods()` and `onlyMethods()` -* [#3949](https://github.com/sebastianbergmann/phpunit/issues/3949): Introduce specialized assertions `assertFileEqualsCanonicalizing()`, `assertFileEqualsIgnoringCase()`, `assertStringEqualsFileCanonicalizing()`, `assertStringEqualsFileIgnoringCase()`, `assertFileNotEqualsCanonicalizing()`, `assertFileNotEqualsIgnoringCase()`, `assertStringNotEqualsFileCanonicalizing()`, and `assertStringNotEqualsFileIgnoringCase()` as alternative to using `assertFileEquals()` etc. with optional parameters - -### Changed - -* [#3860](https://github.com/sebastianbergmann/phpunit/pull/3860): Deprecate invoking PHPUnit commandline test runner with just a class name -* [#3950](https://github.com/sebastianbergmann/phpunit/issues/3950): Deprecate optional parameters of `assertFileEquals()` etc. -* [#3955](https://github.com/sebastianbergmann/phpunit/issues/3955): Deprecate support for doubling multiple interfaces - -### Fixed - -* [#3953](https://github.com/sebastianbergmann/phpunit/issues/3953): Code Coverage for test executed in isolation does not work when the PHAR is used -* [#3967](https://github.com/sebastianbergmann/phpunit/issues/3967): Cannot double interface that extends interface that extends `\Throwable` -* [#3968](https://github.com/sebastianbergmann/phpunit/pull/3968): Test class run in a separate PHP process are passing when `exit` called inside - -[8.5.33]: https://github.com/sebastianbergmann/phpunit/compare/8.5.32...8.5.33 -[8.5.32]: https://github.com/sebastianbergmann/phpunit/compare/8.5.31...8.5.32 -[8.5.31]: https://github.com/sebastianbergmann/phpunit/compare/8.5.30...8.5.31 -[8.5.30]: https://github.com/sebastianbergmann/phpunit/compare/8.5.29...8.5.30 -[8.5.29]: https://github.com/sebastianbergmann/phpunit/compare/8.5.28...8.5.29 -[8.5.28]: https://github.com/sebastianbergmann/phpunit/compare/8.5.27...8.5.28 -[8.5.27]: https://github.com/sebastianbergmann/phpunit/compare/8.5.26...8.5.27 -[8.5.26]: https://github.com/sebastianbergmann/phpunit/compare/8.5.25...8.5.26 -[8.5.25]: https://github.com/sebastianbergmann/phpunit/compare/8.5.24...8.5.25 -[8.5.24]: https://github.com/sebastianbergmann/phpunit/compare/8.5.23...8.5.24 -[8.5.23]: https://github.com/sebastianbergmann/phpunit/compare/8.5.22...8.5.23 -[8.5.22]: https://github.com/sebastianbergmann/phpunit/compare/8.5.21...8.5.22 -[8.5.21]: https://github.com/sebastianbergmann/phpunit/compare/8.5.20...8.5.21 -[8.5.20]: https://github.com/sebastianbergmann/phpunit/compare/8.5.19...8.5.20 -[8.5.19]: https://github.com/sebastianbergmann/phpunit/compare/8.5.18...8.5.19 -[8.5.18]: https://github.com/sebastianbergmann/phpunit/compare/8.5.17...8.5.18 -[8.5.17]: https://github.com/sebastianbergmann/phpunit/compare/8.5.16...8.5.17 -[8.5.16]: https://github.com/sebastianbergmann/phpunit/compare/8.5.15...8.5.16 -[8.5.15]: https://github.com/sebastianbergmann/phpunit/compare/8.5.14...8.5.15 -[8.5.14]: https://github.com/sebastianbergmann/phpunit/compare/8.5.13...8.5.14 -[8.5.13]: https://github.com/sebastianbergmann/phpunit/compare/8.5.12...8.5.13 -[8.5.12]: https://github.com/sebastianbergmann/phpunit/compare/8.5.11...8.5.12 -[8.5.11]: https://github.com/sebastianbergmann/phpunit/compare/8.5.10...8.5.11 -[8.5.10]: https://github.com/sebastianbergmann/phpunit/compare/8.5.9...8.5.10 -[8.5.9]: https://github.com/sebastianbergmann/phpunit/compare/8.5.8...8.5.9 -[8.5.8]: https://github.com/sebastianbergmann/phpunit/compare/8.5.7...8.5.8 -[8.5.7]: https://github.com/sebastianbergmann/phpunit/compare/8.5.6...8.5.7 -[8.5.6]: https://github.com/sebastianbergmann/phpunit/compare/8.5.5...8.5.6 -[8.5.5]: https://github.com/sebastianbergmann/phpunit/compare/8.5.4...8.5.5 -[8.5.4]: https://github.com/sebastianbergmann/phpunit/compare/8.5.3...8.5.4 -[8.5.3]: https://github.com/sebastianbergmann/phpunit/compare/8.5.2...8.5.3 -[8.5.2]: https://github.com/sebastianbergmann/phpunit/compare/8.5.1...8.5.2 -[8.5.1]: https://github.com/sebastianbergmann/phpunit/compare/8.5.0...8.5.1 -[8.5.0]: https://github.com/sebastianbergmann/phpunit/compare/8.4.3...8.5.0 diff --git a/vendor/phpunit/phpunit/ChangeLog-9.6.md b/vendor/phpunit/phpunit/ChangeLog-9.6.md index 30aa32ea..5995d581 100644 --- a/vendor/phpunit/phpunit/ChangeLog-9.6.md +++ b/vendor/phpunit/phpunit/ChangeLog-9.6.md @@ -2,6 +2,24 @@ 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.8] - 2023-05-11 + +### Fixed + +* [#5345](https://github.com/sebastianbergmann/phpunit/issues/5345): No stack trace shown for previous exceptions during bootstrap + +## [9.6.7] - 2023-04-14 + +### Fixed + +* Tests that have `@doesNotPerformAssertions` do not contribute to code coverage + +## [9.6.6] - 2023-03-27 + +### Fixed + +* [#5270](https://github.com/sebastianbergmann/phpunit/issues/5270): `GlobalState::getIniSettingsAsString()` generates code that triggers warnings + ## [9.6.5] - 2023-03-09 ### Changed @@ -46,6 +64,9 @@ 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.8]: https://github.com/sebastianbergmann/phpunit/compare/9.6.7...9.6.8 +[9.6.7]: https://github.com/sebastianbergmann/phpunit/compare/9.6.6...9.6.7 +[9.6.6]: https://github.com/sebastianbergmann/phpunit/compare/9.6.5...9.6.6 [9.6.5]: https://github.com/sebastianbergmann/phpunit/compare/9.6.4...9.6.5 [9.6.4]: https://github.com/sebastianbergmann/phpunit/compare/9.6.3...9.6.4 [9.6.3]: https://github.com/sebastianbergmann/phpunit/compare/9.6.2...9.6.3 diff --git a/vendor/phpunit/phpunit/composer.json b/vendor/phpunit/phpunit/composer.json index c9c8b467..28411d9b 100644 --- a/vendor/phpunit/phpunit/composer.json +++ b/vendor/phpunit/phpunit/composer.json @@ -17,7 +17,8 @@ } ], "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues" + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy" }, "prefer-stable": true, "require": { diff --git a/vendor/phpunit/phpunit/phpunit b/vendor/phpunit/phpunit/phpunit index c8029566..b9f5cf29 100755 --- a/vendor/phpunit/phpunit/phpunit +++ b/vendor/phpunit/phpunit/phpunit @@ -38,22 +38,31 @@ if (version_compare('7.3.0', PHP_VERSION, '>')) { die(1); } -foreach (['dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter'] as $extension) { - if (extension_loaded($extension)) { - continue; - } +$requiredExtensions = ['dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter']; +$unavailableExtensions = array_filter( + $requiredExtensions, + static function ($extension) { + return !extension_loaded($extension); + } +); + +if ([] !== $unavailableExtensions) { fwrite( STDERR, sprintf( - 'PHPUnit requires the "%s" extension.' . PHP_EOL, - $extension + 'PHPUnit requires the "%s" extensions, but the "%s" %s not available.' . PHP_EOL, + implode('", "', $requiredExtensions), + implode('", "', $unavailableExtensions), + count($unavailableExtensions) === 1 ? 'extension is' : 'extensions are' ) ); die(1); } +unset($requiredExtensions, $unavailableExtensions); + if (!ini_get('date.timezone')) { ini_set('date.timezone', 'UTC'); } diff --git a/vendor/phpunit/phpunit/src/Framework/Assert.php b/vendor/phpunit/phpunit/src/Framework/Assert.php index 156220a5..9872b25c 100644 --- a/vendor/phpunit/phpunit/src/Framework/Assert.php +++ b/vendor/phpunit/phpunit/src/Framework/Assert.php @@ -1304,7 +1304,7 @@ abstract class Assert */ public static function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void { - self::createWarning('assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10.'); + self::createWarning('assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectHasProperty() (PHPUnit 10.1.0+) instead.'); if (!self::isValidObjectAttributeName($attributeName)) { throw InvalidArgumentException::create(1, 'valid attribute name'); @@ -1334,7 +1334,7 @@ abstract class Assert */ public static function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void { - self::createWarning('assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10.'); + self::createWarning('assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectNotHasProperty() (PHPUnit 10.1.0+) instead.'); if (!self::isValidObjectAttributeName($attributeName)) { throw InvalidArgumentException::create(1, 'valid attribute name'); diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php index 17e3312c..4810ecae 100644 --- a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php +++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php @@ -72,7 +72,6 @@ trait MockedCloneMethodWithVoidReturnType } } EOT; - private const MOCKED_CLONE_METHOD_WITHOUT_RETURN_TYPE_TRAIT = <<<'EOT' namespace PHPUnit\Framework\MockObject; @@ -84,7 +83,6 @@ trait MockedCloneMethodWithoutReturnType } } EOT; - private const UNMOCKED_CLONE_METHOD_WITH_VOID_RETURN_TYPE_TRAIT = <<<'EOT' namespace PHPUnit\Framework\MockObject; @@ -98,7 +96,6 @@ trait UnmockedCloneMethodWithVoidReturnType } } EOT; - private const UNMOCKED_CLONE_METHOD_WITHOUT_RETURN_TYPE_TRAIT = <<<'EOT' namespace PHPUnit\Framework\MockObject; diff --git a/vendor/phpunit/phpunit/src/Framework/TestResult.php b/vendor/phpunit/phpunit/src/Framework/TestResult.php index 4fde29fa..22150a5a 100644 --- a/vendor/phpunit/phpunit/src/Framework/TestResult.php +++ b/vendor/phpunit/phpunit/src/Framework/TestResult.php @@ -804,6 +804,7 @@ final class TestResult implements Countable } if ($this->beStrictAboutTestsThatDoNotTestAnything && + !$test->doesNotPerformAssertions() && $test->getNumAssertions() === 0) { $risky = true; } diff --git a/vendor/phpunit/phpunit/src/Runner/Version.php b/vendor/phpunit/phpunit/src/Runner/Version.php index 5cfff352..268045a4 100644 --- a/vendor/phpunit/phpunit/src/Runner/Version.php +++ b/vendor/phpunit/phpunit/src/Runner/Version.php @@ -41,7 +41,7 @@ final class Version } if (self::$version === '') { - self::$version = (new VersionId('9.6.5', dirname(__DIR__, 2)))->getVersion(); + self::$version = (new VersionId('9.6.8', dirname(__DIR__, 2)))->getVersion(); } return self::$version; diff --git a/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php index 9030b1db..da488082 100644 --- a/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php +++ b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php @@ -121,7 +121,6 @@ final class Builder 'whitelist=', 'dump-xdebug-filter=', ]; - private const SHORT_OPTIONS = 'd:c:hv'; public function fromParameters(array $parameters, array $additionalLongOptions): Configuration diff --git a/vendor/phpunit/phpunit/src/TextUI/Command.php b/vendor/phpunit/phpunit/src/TextUI/Command.php index 48243caa..0bebad6a 100644 --- a/vendor/phpunit/phpunit/src/TextUI/Command.php +++ b/vendor/phpunit/phpunit/src/TextUI/Command.php @@ -568,16 +568,29 @@ class Command $this->exitWithErrorMessage($t->getMessage()); } - $this->exitWithErrorMessage( - sprintf( - 'Error in bootstrap script: %s:%s%s%s%s', + $message = sprintf( + 'Error in bootstrap script: %s:%s%s%s%s', + get_class($t), + PHP_EOL, + $t->getMessage(), + PHP_EOL, + $t->getTraceAsString() + ); + + while ($t = $t->getPrevious()) { + $message .= sprintf( + '%s%sPrevious error: %s:%s%s%s%s', + PHP_EOL, + PHP_EOL, get_class($t), PHP_EOL, $t->getMessage(), PHP_EOL, - $t->getTraceAsString() - ) - ); + $t->getTraceAsString(), + ); + } + + $this->exitWithErrorMessage($message); } } diff --git a/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php b/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php index 99f0fa9d..408fa133 100644 --- a/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php +++ b/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php @@ -47,23 +47,15 @@ use Throwable; */ class DefaultResultPrinter extends Printer implements ResultPrinter { - public const EVENT_TEST_START = 0; - - public const EVENT_TEST_END = 1; - + public const EVENT_TEST_START = 0; + public const EVENT_TEST_END = 1; public const EVENT_TESTSUITE_START = 2; - - public const EVENT_TESTSUITE_END = 3; - - public const COLOR_NEVER = 'never'; - - public const COLOR_AUTO = 'auto'; - - public const COLOR_ALWAYS = 'always'; - - public const COLOR_DEFAULT = self::COLOR_NEVER; - - private const AVAILABLE_COLORS = [self::COLOR_NEVER, self::COLOR_AUTO, self::COLOR_ALWAYS]; + public const EVENT_TESTSUITE_END = 3; + public const COLOR_NEVER = 'never'; + public const COLOR_AUTO = 'auto'; + public const COLOR_ALWAYS = 'always'; + public const COLOR_DEFAULT = self::COLOR_NEVER; + private const AVAILABLE_COLORS = [self::COLOR_NEVER, self::COLOR_AUTO, self::COLOR_ALWAYS]; /** * @var int diff --git a/vendor/phpunit/phpunit/src/TextUI/Help.php b/vendor/phpunit/phpunit/src/TextUI/Help.php index 084f2a21..82f305dd 100644 --- a/vendor/phpunit/phpunit/src/TextUI/Help.php +++ b/vendor/phpunit/phpunit/src/TextUI/Help.php @@ -27,8 +27,7 @@ use SebastianBergmann\Environment\Console; final class Help { private const LEFT_MARGIN = ' '; - - private const HELP_TEXT = [ + private const HELP_TEXT = [ 'Usage' => [ ['text' => 'phpunit [options] UnitTest.php'], ['text' => 'phpunit [options] '], diff --git a/vendor/phpunit/phpunit/src/TextUI/TestRunner.php b/vendor/phpunit/phpunit/src/TextUI/TestRunner.php index c1362f3a..3ba298e8 100644 --- a/vendor/phpunit/phpunit/src/TextUI/TestRunner.php +++ b/vendor/phpunit/phpunit/src/TextUI/TestRunner.php @@ -88,10 +88,8 @@ use SebastianBergmann\Timer\Timer; */ final class TestRunner extends BaseTestRunner { - public const SUCCESS_EXIT = 0; - - public const FAILURE_EXIT = 1; - + public const SUCCESS_EXIT = 0; + public const FAILURE_EXIT = 1; public const EXCEPTION_EXIT = 2; /** diff --git a/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php b/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php index 648f9edc..5066c4bb 100644 --- a/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php +++ b/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php @@ -67,17 +67,12 @@ final class DocBlock */ public const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/'; - private const REGEX_REQUIRES_VERSION = '/@requires\s+(?PPHP(?:Unit)?)\s+(?P[<>=!]{0,2})\s*(?P[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m'; - + private const REGEX_REQUIRES_VERSION = '/@requires\s+(?PPHP(?:Unit)?)\s+(?P[<>=!]{0,2})\s*(?P[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m'; private const REGEX_REQUIRES_VERSION_CONSTRAINT = '/@requires\s+(?PPHP(?:Unit)?)\s+(?P[\d\t \-.|~^]+)[ \t]*\r?$/m'; - - private const REGEX_REQUIRES_OS = '/@requires\s+(?POS(?:FAMILY)?)\s+(?P.+?)[ \t]*\r?$/m'; - - private const REGEX_REQUIRES_SETTING = '/@requires\s+(?Psetting)\s+(?P([^ ]+?))\s*(?P[\w\.-]+[\w\.]?)?[ \t]*\r?$/m'; - - private const REGEX_REQUIRES = '/@requires\s+(?Pfunction|extension)\s+(?P([^\s<>=!]+))\s*(?P[<>=!]{0,2})\s*(?P[\d\.-]+[\d\.]?)?[ \t]*\r?$/m'; - - private const REGEX_TEST_WITH = '/@testWith\s+/'; + private const REGEX_REQUIRES_OS = '/@requires\s+(?POS(?:FAMILY)?)\s+(?P.+?)[ \t]*\r?$/m'; + private const REGEX_REQUIRES_SETTING = '/@requires\s+(?Psetting)\s+(?P([^ ]+?))\s*(?P[\w\.-]+[\w\.]?)?[ \t]*\r?$/m'; + private const REGEX_REQUIRES = '/@requires\s+(?Pfunction|extension)\s+(?P([^\s<>=!]+))\s*(?P[<>=!]{0,2})\s*(?P[\d\.-]+[\d\.]?)?[ \t]*\r?$/m'; + private const REGEX_TEST_WITH = '/@testWith\s+/'; /** @var string */ private $docComment; diff --git a/vendor/phpunit/phpunit/src/Util/GlobalState.php b/vendor/phpunit/phpunit/src/Util/GlobalState.php index cc5c2228..5cf16bcd 100644 --- a/vendor/phpunit/phpunit/src/Util/GlobalState.php +++ b/vendor/phpunit/phpunit/src/Util/GlobalState.php @@ -9,6 +9,8 @@ */ namespace PHPUnit\Util; +use const PHP_MAJOR_VERSION; +use const PHP_MINOR_VERSION; use function array_keys; use function array_reverse; use function array_shift; @@ -47,6 +49,79 @@ final class GlobalState '_REQUEST', ]; + /** + * @psalm-var array> + */ + private const DEPRECATED_INI_SETTINGS = [ + '7.3' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.func_overload' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'string.strip_tags' => true, + ], + + '7.4' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.func_overload' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'pdo_odbc.db2_instance_name' => true, + 'string.strip_tags' => true, + ], + + '8.0' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + ], + + '8.1' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.2' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.3' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + ]; + /** * @throws Exception */ @@ -106,6 +181,10 @@ final class GlobalState $result = ''; foreach (ini_get_all(null, false) as $key => $value) { + if (self::isIniSettingDeprecated($key)) { + continue; + } + $result .= sprintf( '@ini_set(%s, %s);' . "\n", self::exportVariable($key), @@ -200,4 +279,9 @@ final class GlobalState return $result; } + + private static function isIniSettingDeprecated(string $iniSetting): bool + { + return isset(self::DEPRECATED_INI_SETTINGS[PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION][$iniSetting]); + } } diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php index def16c39..b66eb8b9 100644 --- a/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php +++ b/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php @@ -66,7 +66,6 @@ class CliTestDoxPrinter extends TestDoxPrinter " \e[36m◑\e[0m running tests", " \e[36m◒\e[0m running tests", ]; - private const STATUS_STYLES = [ BaseTestRunner::STATUS_PASSED => [ 'symbol' => '✔', diff --git a/vendor/sebastian/diff/ChangeLog.md b/vendor/sebastian/diff/ChangeLog.md index 9bdcc5b6..a6ccfad7 100644 --- a/vendor/sebastian/diff/ChangeLog.md +++ b/vendor/sebastian/diff/ChangeLog.md @@ -2,6 +2,13 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. +## [4.0.5] - 2023-05-07 + +### Changed + +* [#118](https://github.com/sebastianbergmann/diff/pull/118): Improve performance of `MemoryEfficientLongestCommonSubsequenceCalculator` +* [#119](https://github.com/sebastianbergmann/diff/pull/119): Improve performance of `TimeEfficientLongestCommonSubsequenceCalculator` + ## [4.0.4] - 2020-10-26 ### Fixed @@ -76,6 +83,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt * This component is no longer supported on PHP 5.6 +[4.0.5]: https://github.com/sebastianbergmann/diff/compare/4.0.4...4.0.5 [4.0.4]: https://github.com/sebastianbergmann/diff/compare/4.0.3...4.0.4 [4.0.3]: https://github.com/sebastianbergmann/diff/compare/4.0.2...4.0.3 [4.0.2]: https://github.com/sebastianbergmann/diff/compare/4.0.1...4.0.2 diff --git a/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php b/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php index 0b626eaf..489113b6 100644 --- a/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php +++ b/vendor/sebastian/diff/src/MemoryEfficientLongestCommonSubsequenceCalculator.php @@ -78,7 +78,12 @@ final class MemoryEfficientLongestCommonSubsequenceCalculator implements Longest if ($from[$i] === $to[$j]) { $current[$j + 1] = $prev[$j] + 1; } else { - $current[$j + 1] = max($current[$j], $prev[$j + 1]); + // don't use max() to avoid function call overhead + if ($current[$j] > $prev[$j + 1]) { + $current[$j + 1] = $current[$j]; + } else { + $current[$j + 1] = $prev[$j + 1]; + } } } } diff --git a/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php b/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php index fd19cac7..4e8d951d 100644 --- a/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php +++ b/vendor/sebastian/diff/src/TimeEfficientLongestCommonSubsequenceCalculator.php @@ -37,12 +37,24 @@ final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCo for ($i = 1; $i <= $fromLength; ++$i) { for ($j = 1; $j <= $toLength; ++$j) { - $o = ($j * $width) + $i; - $matrix[$o] = max( - $matrix[$o - 1], - $matrix[$o - $width], - $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0 - ); + $o = ($j * $width) + $i; + + // don't use max() to avoid function call overhead + $firstOrLast = $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0; + + if ($matrix[$o - 1] > $matrix[$o - $width]) { + if ($firstOrLast > $matrix[$o - 1]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - 1]; + } + } else { + if ($firstOrLast > $matrix[$o - $width]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - $width]; + } + } } } diff --git a/vendor/symfony/console/Application.php b/vendor/symfony/console/Application.php index 41548a3e..b7aaa6a2 100644 --- a/vendor/symfony/console/Application.php +++ b/vendor/symfony/console/Application.php @@ -105,11 +105,14 @@ class Application implements ResetInterface /** * @final */ - public function setDispatcher(EventDispatcherInterface $dispatcher) + public function setDispatcher(EventDispatcherInterface $dispatcher): void { $this->dispatcher = $dispatcher; } + /** + * @return void + */ public function setCommandLoader(CommandLoaderInterface $commandLoader) { $this->commandLoader = $commandLoader; @@ -118,12 +121,15 @@ class Application implements ResetInterface public function getSignalRegistry(): SignalRegistry { if (!$this->signalRegistry) { - throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } return $this->signalRegistry; } + /** + * @return void + */ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) { $this->signalsToDispatchEvent = $signalsToDispatchEvent; @@ -317,10 +323,16 @@ class Application implements ResetInterface return $exitCode; } + /** + * @return void + */ public function reset() { } + /** + * @return void + */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; @@ -334,6 +346,9 @@ class Application implements ResetInterface return $this->helperSet ??= $this->getDefaultHelperSet(); } + /** + * @return void + */ public function setDefinition(InputDefinition $definition) { $this->definition = $definition; @@ -404,6 +419,8 @@ class Application implements ResetInterface /** * Sets whether to catch exceptions or not during commands execution. + * + * @return void */ public function setCatchExceptions(bool $boolean) { @@ -420,6 +437,8 @@ class Application implements ResetInterface /** * Sets whether to automatically exit after a command execution or not. + * + * @return void */ public function setAutoExit(bool $boolean) { @@ -436,7 +455,9 @@ class Application implements ResetInterface /** * Sets the application name. - **/ + * + * @return void + */ public function setName(string $name) { $this->name = $name; @@ -452,6 +473,8 @@ class Application implements ResetInterface /** * Sets the application version. + * + * @return void */ public function setVersion(string $version) { @@ -490,6 +513,8 @@ class Application implements ResetInterface * If a Command is not enabled it will not be added. * * @param Command[] $commands An array of commands + * + * @return void */ public function addCommands(array $commands) { @@ -687,9 +712,7 @@ class Application implements ResetInterface if ($alternatives = $this->findAlternatives($name, $allCommands)) { // remove hidden commands - $alternatives = array_filter($alternatives, function ($name) { - return !$this->get($name)->isHidden(); - }); + $alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden()); if (1 == \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; @@ -840,9 +863,7 @@ class Application implements ResetInterface } 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]++/', function ($m) { - return 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; @@ -903,6 +924,8 @@ class Application implements ResetInterface /** * Configures the input and output instances based on the user arguments and options. + * + * @return void */ protected function configureIO(InputInterface $input, OutputInterface $output) { @@ -977,44 +1000,62 @@ class Application implements ResetInterface } } - if ($this->signalsToDispatchEvent) { - $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; + $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; + if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) { + if (!$this->signalRegistry) { + throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } - if ($commandSignals || null !== $this->dispatcher) { - if (!$this->signalRegistry) { - throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); - } + if (Terminal::hasSttyAvailable()) { + $sttyMode = shell_exec('stty -g'); - if (Terminal::hasSttyAvailable()) { - $sttyMode = shell_exec('stty -g'); - - foreach ([\SIGINT, \SIGTERM] as $signal) { - $this->signalRegistry->register($signal, static function () use ($sttyMode) { - shell_exec('stty '.$sttyMode); - }); - } + foreach ([\SIGINT, \SIGTERM] as $signal) { + $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); } } - if (null !== $this->dispatcher) { + if ($this->dispatcher) { + // We register application signals, so that we can dispatch the event foreach ($this->signalsToDispatchEvent as $signal) { $event = new ConsoleSignalEvent($command, $input, $output, $signal); - $this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) { + $this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) { $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); + $exitCode = $event->getExitCode(); - // No more handlers, we try to simulate PHP default behavior - if (!$hasNext) { - if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) { - exit(0); + // If the command is signalable, we call the handleSignal() method + if (\in_array($signal, $commandSignals, true)) { + $exitCode = $command->handleSignal($signal, $exitCode); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); + $exitCode = 0; } } + + if (false !== $exitCode) { + exit($exitCode); + } }); } + + // then we register command signals, but not if already handled after the dispatcher + $commandSignals = array_diff($commandSignals, $this->signalsToDispatchEvent); } foreach ($commandSignals as $signal) { - $this->signalRegistry->register($signal, [$command, 'handleSignal']); + $this->signalRegistry->register($signal, function (int $signal) use ($command): void { + $exitCode = $command->handleSignal($signal); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); + $exitCode = 0; + } + + if (false !== $exitCode) { + exit($exitCode); + } + }); } } @@ -1170,7 +1211,7 @@ class Application implements ResetInterface } } - $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); + $alternatives = array_filter($alternatives, fn ($lev) => $lev < 2 * $threshold); ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); return array_keys($alternatives); @@ -1261,7 +1302,7 @@ class Application implements ResetInterface return $namespaces; } - private function init() + private function init(): void { if ($this->initialized) { return; diff --git a/vendor/symfony/console/CHANGELOG.md b/vendor/symfony/console/CHANGELOG.md index 61c36b0e..3428a57d 100644 --- a/vendor/symfony/console/CHANGELOG.md +++ b/vendor/symfony/console/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +6.3 +--- + + * Add support for choosing exit code while handling signal, or to not exit at all + * Add `ProgressBar::setPlaceholderFormatter` to set a placeholder attached to a instance, instead of being global. + * Add `ReStructuredTextDescriptor` + 6.2 --- diff --git a/vendor/symfony/console/Command/Command.php b/vendor/symfony/console/Command/Command.php index 1e3c1a5a..704b112d 100644 --- a/vendor/symfony/console/Command/Command.php +++ b/vendor/symfony/console/Command/Command.php @@ -141,12 +141,17 @@ class Command * Ignores validation errors. * * This is mainly useful for the help command. + * + * @return void */ public function ignoreValidationErrors() { $this->ignoreValidationErrors = true; } + /** + * @return void + */ public function setApplication(Application $application = null) { if (1 > \func_num_args()) { @@ -162,6 +167,9 @@ class Command $this->fullDefinition = null; } + /** + * @return void + */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; @@ -198,6 +206,8 @@ class Command /** * Configures the current command. + * + * @return void */ protected function configure() { @@ -228,6 +238,8 @@ class Command * This method is executed before the InputDefinition is validated. * This means that this is the only place where the command can * interactively ask for values of missing required arguments. + * + * @return void */ protected function interact(InputInterface $input, OutputInterface $output) { @@ -242,6 +254,8 @@ class Command * * @see InputInterface::bind() * @see InputInterface::validate() + * + * @return void */ protected function initialize(InputInterface $input, OutputInterface $output) { @@ -378,7 +392,7 @@ class Command * * @internal */ - public function mergeApplicationDefinition(bool $mergeArgs = true) + public function mergeApplicationDefinition(bool $mergeArgs = true): void { if (null === $this->application) { return; @@ -702,7 +716,7 @@ class Command * * @throws InvalidArgumentException When the name is invalid */ - private function validateName(string $name) + private function validateName(string $name): void { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); diff --git a/vendor/symfony/console/Command/CompleteCommand.php b/vendor/symfony/console/Command/CompleteCommand.php index e65b334c..058578d8 100644 --- a/vendor/symfony/console/Command/CompleteCommand.php +++ b/vendor/symfony/console/Command/CompleteCommand.php @@ -74,7 +74,7 @@ final class CompleteCommand extends Command ; } - protected function initialize(InputInterface $input, OutputInterface $output) + protected function initialize(InputInterface $input, OutputInterface $output): void { $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL); } @@ -134,12 +134,12 @@ final class CompleteCommand extends Command $completionInput->bind($command->getDefinition()); if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) { - $this->log(' Completing option names for the '.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).' command.'); + $this->log(' Completing option names for the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' command.'); $suggestions->suggestOptions($command->getDefinition()->getOptions()); } else { $this->log([ - ' Completing using the '.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).' class.', + ' Completing using the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' class.', ' Completing '.$completionInput->getCompletionType().' for '.$completionInput->getCompletionName().'', ]); if (null !== $compval = $completionInput->getCompletionValue()) { @@ -155,7 +155,7 @@ final class CompleteCommand extends Command $this->log('Suggestions:'); if ($options = $suggestions->getOptionSuggestions()) { - $this->log(' --'.implode(' --', array_map(function ($o) { return $o->getName(); }, $options))); + $this->log(' --'.implode(' --', array_map(fn ($o) => $o->getName(), $options))); } elseif ($values = $suggestions->getValueSuggestions()) { $this->log(' '.implode(' ', $values)); } else { @@ -173,10 +173,10 @@ final class CompleteCommand extends Command throw $e; } - return self::FAILURE; + return 2; } - return self::SUCCESS; + return 0; } private function createCompletionInput(InputInterface $input): CompletionInput diff --git a/vendor/symfony/console/Command/DumpCompletionCommand.php b/vendor/symfony/console/Command/DumpCompletionCommand.php index 1ad1c0e7..51b613a1 100644 --- a/vendor/symfony/console/Command/DumpCompletionCommand.php +++ b/vendor/symfony/console/Command/DumpCompletionCommand.php @@ -39,7 +39,7 @@ final class DumpCompletionCommand extends Command private array $supportedShells; - protected function configure() + protected function configure(): void { $fullCommand = $_SERVER['PHP_SELF']; $commandName = basename($fullCommand); @@ -48,14 +48,16 @@ final class DumpCompletionCommand extends Command $shell = $this->guessShell(); [$rcFile, $completionFile] = match ($shell) { 'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"], - 'zsh' => ['~/.zshrc', '$fpath[1]/'.$commandName], + 'zsh' => ['~/.zshrc', '$fpath[1]/_'.$commandName], default => ['~/.bashrc', "/etc/bash_completion.d/$commandName"], }; + $supportedShells = implode(', ', $this->getSupportedShells()); + $this ->setHelp(<<%command.name% command dumps the shell completion script required -to use shell autocompletion (currently, bash and fish completion is supported). +to use shell autocompletion (currently, {$supportedShells} completion are supported). Static installation ------------------- @@ -94,7 +96,7 @@ EOH if ($input->getOption('debug')) { $this->tailDebugLog($commandName, $output); - return self::SUCCESS; + return 0; } $shell = $input->getArgument('shell') ?? self::guessShell(); @@ -111,12 +113,12 @@ EOH $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } - return self::INVALID; + return 2; } $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], file_get_contents($completionFile))); - return self::SUCCESS; + return 0; } private static function guessShell(): string @@ -141,8 +143,19 @@ EOH */ private function getSupportedShells(): array { - return $this->supportedShells ??= array_map(function ($f) { - return pathinfo($f, \PATHINFO_EXTENSION); - }, glob(__DIR__.'/../Resources/completion.*')); + if (isset($this->supportedShells)) { + return $this->supportedShells; + } + + $shells = []; + + foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) { + if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) { + $shells[] = $file->getExtension(); + } + } + sort($shells); + + return $this->supportedShells = $shells; } } diff --git a/vendor/symfony/console/Command/HelpCommand.php b/vendor/symfony/console/Command/HelpCommand.php index d4134e17..e6447b05 100644 --- a/vendor/symfony/console/Command/HelpCommand.php +++ b/vendor/symfony/console/Command/HelpCommand.php @@ -27,6 +27,9 @@ class HelpCommand extends Command { private Command $command; + /** + * @return void + */ protected function configure() { $this->ignoreValidationErrors(); @@ -34,12 +37,8 @@ class HelpCommand extends Command $this ->setName('help') ->setDefinition([ - new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', function () { - return array_keys((new ApplicationDescription($this->getApplication()))->getCommands()); - }), - new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () { - return (new DescriptorHelper())->getFormats(); - }), + new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', fn () => array_keys((new ApplicationDescription($this->getApplication()))->getCommands())), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'), ]) ->setDescription('Display help for a command') @@ -58,6 +57,9 @@ EOF ; } + /** + * @return void + */ public function setCommand(Command $command) { $this->command = $command; diff --git a/vendor/symfony/console/Command/ListCommand.php b/vendor/symfony/console/Command/ListCommand.php index cab88b43..5850c3d7 100644 --- a/vendor/symfony/console/Command/ListCommand.php +++ b/vendor/symfony/console/Command/ListCommand.php @@ -25,18 +25,17 @@ use Symfony\Component\Console\Output\OutputInterface; */ class ListCommand extends Command { + /** + * @return void + */ protected function configure() { $this ->setName('list') ->setDefinition([ - new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, function () { - return array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces()); - }), + new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, fn () => array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces())), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), - new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () { - return (new DescriptorHelper())->getFormats(); - }), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'), ]) ->setDescription('List commands') diff --git a/vendor/symfony/console/Command/LockableTrait.php b/vendor/symfony/console/Command/LockableTrait.php index 67923a9e..c1006a65 100644 --- a/vendor/symfony/console/Command/LockableTrait.php +++ b/vendor/symfony/console/Command/LockableTrait.php @@ -32,7 +32,7 @@ trait LockableTrait private function lock(string $name = null, bool $blocking = false): bool { if (!class_exists(SemaphoreStore::class)) { - throw new LogicException('To enable the locking feature you must install the symfony/lock component.'); + throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".'); } if (null !== $this->lock) { @@ -58,7 +58,7 @@ trait LockableTrait /** * Releases the command lock if there is one. */ - private function release() + private function release(): void { if ($this->lock) { $this->lock->release(); diff --git a/vendor/symfony/console/Command/SignalableCommandInterface.php b/vendor/symfony/console/Command/SignalableCommandInterface.php index d439728b..4d087600 100644 --- a/vendor/symfony/console/Command/SignalableCommandInterface.php +++ b/vendor/symfony/console/Command/SignalableCommandInterface.php @@ -25,6 +25,10 @@ interface SignalableCommandInterface /** * The method will be called when the application is signaled. + * + * @param int|false $previousExitCode + + * @return int|false The exit code to return or false to continue the normal execution */ - public function handleSignal(int $signal): void; + public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */); } diff --git a/vendor/symfony/console/Completion/CompletionInput.php b/vendor/symfony/console/Completion/CompletionInput.php index 3ef8db5d..800b7235 100644 --- a/vendor/symfony/console/Completion/CompletionInput.php +++ b/vendor/symfony/console/Completion/CompletionInput.php @@ -34,7 +34,7 @@ final class CompletionInput extends ArgvInput private $tokens; private $currentIndex; private $completionType; - private $completionName = null; + private $completionName; private $completionValue = ''; /** diff --git a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php index 62c80c3b..27705ddb 100644 --- a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php +++ b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -29,6 +29,9 @@ use Symfony\Component\DependencyInjection\TypedReference; */ class AddConsoleCommandPass implements CompilerPassInterface { + /** + * @return void + */ public function process(ContainerBuilder $container) { $commandServices = $container->findTaggedServiceIds('console.command', true); diff --git a/vendor/symfony/console/Descriptor/ApplicationDescription.php b/vendor/symfony/console/Descriptor/ApplicationDescription.php index 2158339e..f8ed1804 100644 --- a/vendor/symfony/console/Descriptor/ApplicationDescription.php +++ b/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -79,7 +79,7 @@ class ApplicationDescription return $this->commands[$name] ?? $this->aliases[$name]; } - private function inspectApplication() + private function inspectApplication(): void { $this->commands = []; $this->namespaces = []; diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php index 1476f575..7b2509c6 100644 --- a/vendor/symfony/console/Descriptor/Descriptor.php +++ b/vendor/symfony/console/Descriptor/Descriptor.php @@ -26,12 +26,9 @@ use Symfony\Component\Console\Output\OutputInterface; */ abstract class Descriptor implements DescriptorInterface { - /** - * @var OutputInterface - */ - protected $output; + protected OutputInterface $output; - public function describe(OutputInterface $output, object $object, array $options = []) + public function describe(OutputInterface $output, object $object, array $options = []): void { $this->output = $output; @@ -45,10 +42,7 @@ abstract class Descriptor implements DescriptorInterface }; } - /** - * Writes content to output. - */ - protected function write(string $content, bool $decorated = false) + protected function write(string $content, bool $decorated = false): void { $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); } @@ -56,25 +50,25 @@ abstract class Descriptor implements DescriptorInterface /** * Describes an InputArgument instance. */ - abstract protected function describeInputArgument(InputArgument $argument, array $options = []); + abstract protected function describeInputArgument(InputArgument $argument, array $options = []): void; /** * Describes an InputOption instance. */ - abstract protected function describeInputOption(InputOption $option, array $options = []); + abstract protected function describeInputOption(InputOption $option, array $options = []): void; /** * Describes an InputDefinition instance. */ - abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []); + abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []): void; /** * Describes a Command instance. */ - abstract protected function describeCommand(Command $command, array $options = []); + abstract protected function describeCommand(Command $command, array $options = []): void; /** * Describes an Application instance. */ - abstract protected function describeApplication(Application $application, array $options = []); + abstract protected function describeApplication(Application $application, array $options = []): void; } diff --git a/vendor/symfony/console/Descriptor/DescriptorInterface.php b/vendor/symfony/console/Descriptor/DescriptorInterface.php index ebea3036..ab468a25 100644 --- a/vendor/symfony/console/Descriptor/DescriptorInterface.php +++ b/vendor/symfony/console/Descriptor/DescriptorInterface.php @@ -20,5 +20,8 @@ use Symfony\Component\Console\Output\OutputInterface; */ interface DescriptorInterface { + /** + * @return void + */ public function describe(OutputInterface $output, object $object, array $options = []); } diff --git a/vendor/symfony/console/Descriptor/JsonDescriptor.php b/vendor/symfony/console/Descriptor/JsonDescriptor.php index 6f79a17a..95630370 100644 --- a/vendor/symfony/console/Descriptor/JsonDescriptor.php +++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php @@ -26,12 +26,12 @@ use Symfony\Component\Console\Input\InputOption; */ class JsonDescriptor extends Descriptor { - protected function describeInputArgument(InputArgument $argument, array $options = []) + protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->writeData($this->getInputArgumentData($argument), $options); } - protected function describeInputOption(InputOption $option, array $options = []) + protected function describeInputOption(InputOption $option, array $options = []): void { $this->writeData($this->getInputOptionData($option), $options); if ($option->isNegatable()) { @@ -39,17 +39,17 @@ class JsonDescriptor extends Descriptor } } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $this->writeData($this->getInputDefinitionData($definition), $options); } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options); } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace, true); @@ -81,7 +81,7 @@ class JsonDescriptor extends Descriptor /** * Writes data as json. */ - private function writeData(array $data, array $options) + private function writeData(array $data, array $options): void { $flags = $options['json_encoding'] ?? 0; diff --git a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php index fbd9c534..b3f16ee9 100644 --- a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php +++ b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php @@ -28,7 +28,7 @@ use Symfony\Component\Console\Output\OutputInterface; */ class MarkdownDescriptor extends Descriptor { - public function describe(OutputInterface $output, object $object, array $options = []) + public function describe(OutputInterface $output, object $object, array $options = []): void { $decorated = $output->isDecorated(); $output->setDecorated(false); @@ -38,12 +38,12 @@ class MarkdownDescriptor extends Descriptor $output->setDecorated($decorated); } - protected function write(string $content, bool $decorated = true) + protected function write(string $content, bool $decorated = true): void { parent::write($content, $decorated); } - protected function describeInputArgument(InputArgument $argument, array $options = []) + protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->write( '#### `'.($argument->getName() ?: '')."`\n\n" @@ -54,7 +54,7 @@ class MarkdownDescriptor extends Descriptor ); } - protected function describeInputOption(InputOption $option, array $options = []) + protected function describeInputOption(InputOption $option, array $options = []): void { $name = '--'.$option->getName(); if ($option->isNegatable()) { @@ -75,15 +75,13 @@ class MarkdownDescriptor extends Descriptor ); } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { if ($showArguments = \count($definition->getArguments()) > 0) { $this->write('### Arguments'); foreach ($definition->getArguments() as $argument) { $this->write("\n\n"); - if (null !== $describeInputArgument = $this->describeInputArgument($argument)) { - $this->write($describeInputArgument); - } + $this->describeInputArgument($argument); } } @@ -95,14 +93,12 @@ class MarkdownDescriptor extends Descriptor $this->write('### Options'); foreach ($definition->getOptions() as $option) { $this->write("\n\n"); - if (null !== $describeInputOption = $this->describeInputOption($option)) { - $this->write($describeInputOption); - } + $this->describeInputOption($option); } } } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { if ($options['short'] ?? false) { $this->write( @@ -110,9 +106,7 @@ class MarkdownDescriptor extends Descriptor .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') .'### Usage'."\n\n" - .array_reduce($command->getAliases(), function ($carry, $usage) { - return $carry.'* `'.$usage.'`'."\n"; - }) + .array_reduce($command->getAliases(), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") ); return; @@ -125,9 +119,7 @@ class MarkdownDescriptor extends Descriptor .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') .'### Usage'."\n\n" - .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) { - return $carry.'* `'.$usage.'`'."\n"; - }) + .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") ); if ($help = $command->getProcessedHelp()) { @@ -142,7 +134,7 @@ class MarkdownDescriptor extends Descriptor } } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); @@ -157,16 +149,12 @@ class MarkdownDescriptor extends Descriptor } $this->write("\n\n"); - $this->write(implode("\n", array_map(function ($commandName) use ($description) { - return 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) { $this->write("\n\n"); - if (null !== $describeCommand = $this->describeCommand($command, $options)) { - $this->write($describeCommand); - } + $this->describeCommand($command, $options); } } diff --git a/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php new file mode 100644 index 00000000..d4423fd3 --- /dev/null +++ b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php @@ -0,0 +1,272 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Descriptor; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\String\UnicodeString; + +class ReStructuredTextDescriptor extends Descriptor +{ + //

+ private string $partChar = '='; + //

+ private string $chapterChar = '-'; + //

+ private string $sectionChar = '~'; + //

+ private string $subsectionChar = '.'; + //

+ private string $subsubsectionChar = '^'; + //
+ private string $paragraphsChar = '"'; + + private array $visibleNamespaces = []; + + public function describe(OutputInterface $output, object $object, array $options = []): void + { + $decorated = $output->isDecorated(); + $output->setDecorated(false); + + parent::describe($output, $object, $options); + + $output->setDecorated($decorated); + } + + /** + * Override parent method to set $decorated = true. + */ + protected function write(string $content, bool $decorated = true): void + { + parent::write($content, $decorated); + } + + protected function describeInputArgument(InputArgument $argument, array $options = []): void + { + $this->write( + $argument->getName() ?: ''."\n".str_repeat($this->paragraphsChar, Helper::width($argument->getName()))."\n\n" + .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '') + .'- **Is required**: '.($argument->isRequired() ? 'yes' : 'no')."\n" + .'- **Is array**: '.($argument->isArray() ? 'yes' : 'no')."\n" + .'- **Default**: ``'.str_replace("\n", '', var_export($argument->getDefault(), true)).'``' + ); + } + + protected function describeInputOption(InputOption $option, array $options = []): void + { + $name = '\-\-'.$option->getName(); + if ($option->isNegatable()) { + $name .= '|\-\-no-'.$option->getName(); + } + if ($option->getShortcut()) { + $name .= '|-'.str_replace('|', '|-', $option->getShortcut()); + } + + $optionDescription = $option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n\n", $option->getDescription())."\n\n" : ''; + $optionDescription = (new UnicodeString($optionDescription))->ascii(); + $this->write( + $name."\n".str_repeat($this->paragraphsChar, Helper::width($name))."\n\n" + .$optionDescription + .'- **Accept value**: '.($option->acceptValue() ? 'yes' : 'no')."\n" + .'- **Is value required**: '.($option->isValueRequired() ? 'yes' : 'no')."\n" + .'- **Is multiple**: '.($option->isArray() ? 'yes' : 'no')."\n" + .'- **Is negatable**: '.($option->isNegatable() ? 'yes' : 'no')."\n" + .'- **Default**: ``'.str_replace("\n", '', var_export($option->getDefault(), true)).'``'."\n" + ); + } + + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void + { + if ($showArguments = ((bool) $definition->getArguments())) { + $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n"; + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + $this->describeInputArgument($argument); + } + } + + if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) { + if ($showArguments) { + $this->write("\n\n"); + } + + $this->write("Options\n".str_repeat($this->subsubsectionChar, 7)."\n\n"); + foreach ($nonDefaultOptions as $option) { + $this->describeInputOption($option); + $this->write("\n"); + } + } + } + + protected function describeCommand(Command $command, array $options = []): void + { + if ($options['short'] ?? false) { + $this->write( + '``'.$command->getName()."``\n" + .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + ."Usage\n".str_repeat($this->paragraphsChar, 5)."\n\n" + .array_reduce($command->getAliases(), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") + ); + + return; + } + + $command->mergeApplicationDefinition(false); + + foreach ($command->getAliases() as $alias) { + $this->write('.. _'.$alias.":\n\n"); + } + $this->write( + $command->getName()."\n" + .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" + .($command->getDescription() ? $command->getDescription()."\n\n" : '') + ."Usage\n".str_repeat($this->subsubsectionChar, 5)."\n\n" + .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") + ); + + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->write("\n\n"); + $this->describeInputDefinition($definition); + } + } + + protected function describeApplication(Application $application, array $options = []): void + { + $description = new ApplicationDescription($application, $options['namespace'] ?? null); + $title = $this->getApplicationTitle($application); + + $this->write($title."\n".str_repeat($this->partChar, Helper::width($title))); + $this->createTableOfContents($description, $application); + $this->describeCommands($application, $options); + } + + private function getApplicationTitle(Application $application): string + { + if ('UNKNOWN' === $application->getName()) { + return 'Console Tool'; + } + if ('UNKNOWN' !== $application->getVersion()) { + return sprintf('%s %s', $application->getName(), $application->getVersion()); + } + + return $application->getName(); + } + + private function describeCommands($application, array $options): void + { + $title = 'Commands'; + $this->write("\n\n$title\n".str_repeat($this->chapterChar, Helper::width($title))."\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + $this->write('Global'."\n".str_repeat($this->sectionChar, Helper::width('Global'))."\n\n"); + } else { + $commands = $application->all($namespace); + $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); + } + + foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) { + $this->describeCommand($command, $options); + $this->write("\n\n"); + } + } + } + + private function createTableOfContents(ApplicationDescription $description, Application $application): void + { + $this->setVisibleNamespaces($description); + $chapterTitle = 'Table of Contents'; + $this->write("\n\n$chapterTitle\n".str_repeat($this->chapterChar, Helper::width($chapterTitle))."\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + } else { + $commands = $application->all($namespace); + $this->write("\n\n"); + $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); + } + $commands = $this->removeAliasesAndHiddenCommands($commands); + + $this->write("\n\n"); + $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands)))); + } + } + + private function getNonDefaultOptions(InputDefinition $definition): array + { + $globalOptions = [ + 'help', + 'quiet', + 'verbose', + 'version', + 'ansi', + 'no-interaction', + ]; + $nonDefaultOptions = []; + foreach ($definition->getOptions() as $option) { + // Skip global options. + if (!\in_array($option->getName(), $globalOptions)) { + $nonDefaultOptions[] = $option; + } + } + + return $nonDefaultOptions; + } + + private function setVisibleNamespaces(ApplicationDescription $description): void + { + $commands = $description->getCommands(); + foreach ($description->getNamespaces() as $namespace) { + try { + $namespaceCommands = $namespace['commands']; + foreach ($namespaceCommands as $key => $commandName) { + if (!\array_key_exists($commandName, $commands)) { + // If the array key does not exist, then this is an alias. + unset($namespaceCommands[$key]); + } elseif ($commands[$commandName]->isHidden()) { + unset($namespaceCommands[$key]); + } + } + if (!$namespaceCommands) { + // If the namespace contained only aliases or hidden commands, skip the namespace. + continue; + } + } catch (\Exception) { + } + $this->visibleNamespaces[] = $namespace['id']; + } + } + + private function removeAliasesAndHiddenCommands(array $commands): array + { + foreach ($commands as $key => $command) { + if ($command->isHidden() || \in_array($key, $command->getAliases(), true)) { + unset($commands[$key]); + } + } + unset($commands['completion']); + + return $commands; + } +} diff --git a/vendor/symfony/console/Descriptor/TextDescriptor.php b/vendor/symfony/console/Descriptor/TextDescriptor.php index 48a0b42a..d04d1023 100644 --- a/vendor/symfony/console/Descriptor/TextDescriptor.php +++ b/vendor/symfony/console/Descriptor/TextDescriptor.php @@ -28,7 +28,7 @@ use Symfony\Component\Console\Input\InputOption; */ class TextDescriptor extends Descriptor { - protected function describeInputArgument(InputArgument $argument, array $options = []) + 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())); @@ -48,7 +48,7 @@ class TextDescriptor extends Descriptor ), $options); } - protected function describeInputOption(InputOption $option, 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())); @@ -83,7 +83,7 @@ class TextDescriptor extends Descriptor ), $options); } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); foreach ($definition->getArguments() as $argument) { @@ -122,7 +122,7 @@ class TextDescriptor extends Descriptor } } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { $command->mergeApplicationDefinition(false); @@ -157,7 +157,7 @@ class TextDescriptor extends Descriptor } } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); @@ -193,9 +193,7 @@ class TextDescriptor extends Descriptor } // calculate max. width based on available commands per namespace - $width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) { - return array_intersect($namespace['commands'], array_keys($commands)); - }, array_values($namespaces))))); + $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); @@ -204,9 +202,7 @@ class TextDescriptor extends Descriptor } foreach ($namespaces as $namespace) { - $namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) { - return isset($commands[$name]); - }); + $namespace['commands'] = array_filter($namespace['commands'], fn ($name) => isset($commands[$name])); if (!$namespace['commands']) { continue; @@ -230,7 +226,7 @@ class TextDescriptor extends Descriptor } } - private function writeText(string $content, array $options = []) + private function writeText(string $content, array $options = []): void { $this->write( isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content, diff --git a/vendor/symfony/console/Descriptor/XmlDescriptor.php b/vendor/symfony/console/Descriptor/XmlDescriptor.php index f4643a9a..72580fd9 100644 --- a/vendor/symfony/console/Descriptor/XmlDescriptor.php +++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php @@ -120,27 +120,27 @@ class XmlDescriptor extends Descriptor return $dom; } - protected function describeInputArgument(InputArgument $argument, array $options = []) + protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->writeDocument($this->getInputArgumentDocument($argument)); } - protected function describeInputOption(InputOption $option, array $options = []) + protected function describeInputOption(InputOption $option, array $options = []): void { $this->writeDocument($this->getInputOptionDocument($option)); } - protected function describeInputDefinition(InputDefinition $definition, array $options = []) + protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $this->writeDocument($this->getInputDefinitionDocument($definition)); } - protected function describeCommand(Command $command, array $options = []) + protected function describeCommand(Command $command, array $options = []): void { $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false)); } - protected function describeApplication(Application $application, array $options = []) + protected function describeApplication(Application $application, array $options = []): void { $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false)); } @@ -148,7 +148,7 @@ class XmlDescriptor extends Descriptor /** * Appends document children to parent node. */ - private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) + private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent): void { foreach ($importedParent->childNodes as $childNode) { $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true)); @@ -158,7 +158,7 @@ class XmlDescriptor extends Descriptor /** * Writes DOM document. */ - private function writeDocument(\DOMDocument $dom) + private function writeDocument(\DOMDocument $dom): void { $dom->formatOutput = true; $this->write($dom->saveXML()); diff --git a/vendor/symfony/console/Event/ConsoleSignalEvent.php b/vendor/symfony/console/Event/ConsoleSignalEvent.php index 766af691..95af1f91 100644 --- a/vendor/symfony/console/Event/ConsoleSignalEvent.php +++ b/vendor/symfony/console/Event/ConsoleSignalEvent.php @@ -21,15 +21,36 @@ use Symfony\Component\Console\Output\OutputInterface; final class ConsoleSignalEvent extends ConsoleEvent { private int $handlingSignal; + private int|false $exitCode; - public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal) + public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, int|false $exitCode = 0) { parent::__construct($command, $input, $output); $this->handlingSignal = $handlingSignal; + $this->exitCode = $exitCode; } public function getHandlingSignal(): int { return $this->handlingSignal; } + + public function setExitCode(int $exitCode): void + { + if ($exitCode < 0 || $exitCode > 255) { + throw new \InvalidArgumentException('Exit code must be between 0 and 255.'); + } + + $this->exitCode = $exitCode; + } + + public function abortExit(): void + { + $this->exitCode = false; + } + + public function getExitCode(): int|false + { + return $this->exitCode; + } } diff --git a/vendor/symfony/console/EventListener/ErrorListener.php b/vendor/symfony/console/EventListener/ErrorListener.php index 773a13a1..9925a5f7 100644 --- a/vendor/symfony/console/EventListener/ErrorListener.php +++ b/vendor/symfony/console/EventListener/ErrorListener.php @@ -31,6 +31,9 @@ class ErrorListener implements EventSubscriberInterface $this->logger = $logger; } + /** + * @return void + */ public function onConsoleError(ConsoleErrorEvent $event) { if (null === $this->logger) { @@ -48,6 +51,9 @@ class ErrorListener implements EventSubscriberInterface $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); } + /** + * @return void + */ public function onConsoleTerminate(ConsoleTerminateEvent $event) { if (null === $this->logger) { diff --git a/vendor/symfony/console/Formatter/OutputFormatter.php b/vendor/symfony/console/Formatter/OutputFormatter.php index 38e75c31..9cb63104 100644 --- a/vendor/symfony/console/Formatter/OutputFormatter.php +++ b/vendor/symfony/console/Formatter/OutputFormatter.php @@ -81,6 +81,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface $this->styleStack = new OutputFormatterStyleStack(); } + /** + * @return void + */ public function setDecorated(bool $decorated) { $this->decorated = $decorated; @@ -91,6 +94,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface return $this->decorated; } + /** + * @return void + */ public function setStyle(string $name, OutputFormatterStyleInterface $style) { $this->styles[strtolower($name)] = $style; @@ -115,6 +121,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface return $this->formatAndWrap($message, 0); } + /** + * @return string + */ public function formatAndWrap(?string $message, int $width) { if (null === $message) { diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php index b94e51de..433cd419 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterInterface.php +++ b/vendor/symfony/console/Formatter/OutputFormatterInterface.php @@ -20,6 +20,8 @@ interface OutputFormatterInterface { /** * Sets the decorated flag. + * + * @return void */ public function setDecorated(bool $decorated); @@ -30,6 +32,8 @@ interface OutputFormatterInterface /** * Sets a new style. + * + * @return void */ public function setStyle(string $name, OutputFormatterStyleInterface $style); diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php index 1659986e..346a474c 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyle.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -38,6 +38,9 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); } + /** + * @return void + */ public function setForeground(string $color = null) { if (1 > \func_num_args()) { @@ -46,6 +49,9 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); } + /** + * @return void + */ public function setBackground(string $color = null) { if (1 > \func_num_args()) { @@ -59,12 +65,18 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->href = $url; } + /** + * @return void + */ public function setOption(string $option) { $this->options[] = $option; $this->color = new Color($this->foreground, $this->background, $this->options); } + /** + * @return void + */ public function unsetOption(string $option) { $pos = array_search($option, $this->options); @@ -75,6 +87,9 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface $this->color = new Color($this->foreground, $this->background, $this->options); } + /** + * @return void + */ public function setOptions(array $options) { $this->color = new Color($this->foreground, $this->background, $this->options = $options); @@ -83,7 +98,8 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface public function apply(string $text): string { $this->handlesHrefGracefully ??= 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR') - && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100); + && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100) + && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); if (null !== $this->href && $this->handlesHrefGracefully) { $text = "\033]8;;$this->href\033\\$text\033]8;;\033\\"; diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php index 7ed67d9a..3b15098c 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php @@ -20,26 +20,36 @@ interface OutputFormatterStyleInterface { /** * Sets style foreground color. + * + * @return void */ public function setForeground(?string $color); /** * Sets style background color. + * + * @return void */ public function setBackground(?string $color); /** * Sets some specific style option. + * + * @return void */ public function setOption(string $option); /** * Unsets some specific style option. + * + * @return void */ public function unsetOption(string $option); /** * Sets multiple style options at once. + * + * @return void */ public function setOptions(array $options); diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php index 2c5cdf9b..f98c2eff 100644 --- a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -34,6 +34,8 @@ class OutputFormatterStyleStack implements ResetInterface /** * Resets stack (ie. empty internal arrays). + * + * @return void */ public function reset() { @@ -42,6 +44,8 @@ class OutputFormatterStyleStack implements ResetInterface /** * Pushes a style in the stack. + * + * @return void */ public function push(OutputFormatterStyleInterface $style) { diff --git a/vendor/symfony/console/Helper/DescriptorHelper.php b/vendor/symfony/console/Helper/DescriptorHelper.php index 3015ff08..eb32bce8 100644 --- a/vendor/symfony/console/Helper/DescriptorHelper.php +++ b/vendor/symfony/console/Helper/DescriptorHelper.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Descriptor\DescriptorInterface; use Symfony\Component\Console\Descriptor\JsonDescriptor; use Symfony\Component\Console\Descriptor\MarkdownDescriptor; +use Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor; use Symfony\Component\Console\Descriptor\TextDescriptor; use Symfony\Component\Console\Descriptor\XmlDescriptor; use Symfony\Component\Console\Exception\InvalidArgumentException; @@ -38,6 +39,7 @@ class DescriptorHelper extends Helper ->register('xml', new XmlDescriptor()) ->register('json', new JsonDescriptor()) ->register('md', new MarkdownDescriptor()) + ->register('rst', new ReStructuredTextDescriptor()) ; } @@ -48,6 +50,8 @@ class DescriptorHelper extends Helper * * format: string, the output format name * * raw_text: boolean, sets output type as raw * + * @return void + * * @throws InvalidArgumentException when the given format is not supported */ public function describe(OutputInterface $output, ?object $object, array $options = []) diff --git a/vendor/symfony/console/Helper/Dumper.php b/vendor/symfony/console/Helper/Dumper.php index ac7571ce..8c6a94d5 100644 --- a/vendor/symfony/console/Helper/Dumper.php +++ b/vendor/symfony/console/Helper/Dumper.php @@ -40,14 +40,12 @@ final class Dumper return rtrim($dumper->dump(($this->cloner ??= new VarCloner())->cloneVar($var)->withRefHandles(false), true)); }; } else { - $this->handler = function ($var): string { - return match (true) { - null === $var => 'null', - true === $var => 'true', - false === $var => 'false', - \is_string($var) => '"'.$var.'"', - default => rtrim(print_r($var, true)), - }; + $this->handler = fn ($var): string => match (true) { + null === $var => 'null', + true === $var => 'true', + false === $var => 'false', + \is_string($var) => '"'.$var.'"', + default => rtrim(print_r($var, true)), }; } } diff --git a/vendor/symfony/console/Helper/Helper.php b/vendor/symfony/console/Helper/Helper.php index 920196e0..3631b30f 100644 --- a/vendor/symfony/console/Helper/Helper.php +++ b/vendor/symfony/console/Helper/Helper.php @@ -21,8 +21,11 @@ use Symfony\Component\String\UnicodeString; */ abstract class Helper implements HelperInterface { - protected $helperSet = null; + protected $helperSet; + /** + * @return void + */ public function setHelperSet(HelperSet $helperSet = null) { if (1 > \func_num_args()) { @@ -88,6 +91,9 @@ abstract class Helper implements HelperInterface return mb_substr($string, $from, $length, $encoding); } + /** + * @return string + */ public static function formatTime(int|float $secs) { static $timeFormats = [ @@ -117,6 +123,9 @@ abstract class Helper implements HelperInterface } } + /** + * @return string + */ public static function formatMemory(int $memory) { if ($memory >= 1024 * 1024 * 1024) { @@ -134,6 +143,9 @@ abstract class Helper implements HelperInterface return sprintf('%d B', $memory); } + /** + * @return string + */ public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) { $isDecorated = $formatter->isDecorated(); diff --git a/vendor/symfony/console/Helper/HelperInterface.php b/vendor/symfony/console/Helper/HelperInterface.php index 2762cdf0..ab626c93 100644 --- a/vendor/symfony/console/Helper/HelperInterface.php +++ b/vendor/symfony/console/Helper/HelperInterface.php @@ -20,6 +20,8 @@ interface HelperInterface { /** * Sets the helper set associated with this helper. + * + * @return void */ public function setHelperSet(?HelperSet $helperSet); diff --git a/vendor/symfony/console/Helper/HelperSet.php b/vendor/symfony/console/Helper/HelperSet.php index cefe62be..dc5d499c 100644 --- a/vendor/symfony/console/Helper/HelperSet.php +++ b/vendor/symfony/console/Helper/HelperSet.php @@ -35,6 +35,9 @@ class HelperSet implements \IteratorAggregate } } + /** + * @return void + */ public function set(HelperInterface $helper, string $alias = null) { $this->helpers[$helper->getName()] = $helper; diff --git a/vendor/symfony/console/Helper/InputAwareHelper.php b/vendor/symfony/console/Helper/InputAwareHelper.php index ba81e377..6f822597 100644 --- a/vendor/symfony/console/Helper/InputAwareHelper.php +++ b/vendor/symfony/console/Helper/InputAwareHelper.php @@ -23,6 +23,9 @@ abstract class InputAwareHelper extends Helper implements InputAwareInterface { protected $input; + /** + * @return void + */ public function setInput(InputInterface $input) { $this->input = $input; diff --git a/vendor/symfony/console/Helper/ProgressBar.php b/vendor/symfony/console/Helper/ProgressBar.php index 0d112609..19faea47 100644 --- a/vendor/symfony/console/Helper/ProgressBar.php +++ b/vendor/symfony/console/Helper/ProgressBar.php @@ -59,6 +59,7 @@ final class ProgressBar private Terminal $terminal; private ?string $previousMessage = null; private Cursor $cursor; + private array $placeholders = []; private static array $formatters; private static array $formats; @@ -94,12 +95,12 @@ final class ProgressBar } /** - * Sets a placeholder formatter for a given name. + * Sets a placeholder formatter for a given name, globally for all instances of ProgressBar. * * This method also allow you to override an existing placeholder. * - * @param string $name The placeholder name (including the delimiter char like %) - * @param callable $callable A PHP callable + * @param string $name The placeholder name (including the delimiter char like %) + * @param callable(ProgressBar):string $callable A PHP callable */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void { @@ -120,6 +121,26 @@ final class ProgressBar return self::$formatters[$name] ?? null; } + /** + * Sets a placeholder formatter for a given name, for this instance only. + * + * @param callable(ProgressBar):string $callable A PHP callable + */ + public function setPlaceholderFormatter(string $name, callable $callable): void + { + $this->placeholders[$name] = $callable; + } + + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + */ + public function getPlaceholderFormatter(string $name): ?callable + { + return $this->placeholders[$name] ?? $this::getPlaceholderFormatterDefinition($name); + } + /** * Sets a format for a given name. * @@ -157,12 +178,12 @@ final class ProgressBar * @param string $message The text to associate with the placeholder * @param string $name The name of the placeholder */ - public function setMessage(string $message, string $name = 'message') + public function setMessage(string $message, string $name = 'message'): void { $this->messages[$name] = $message; } - public function getMessage(string $name = 'message') + public function getMessage(string $name = 'message'): string { return $this->messages[$name]; } @@ -215,7 +236,7 @@ final class ProgressBar return round((time() - $this->startTime) / ($this->step - $this->startingStep) * ($this->max - $this->step)); } - public function setBarWidth(int $size) + public function setBarWidth(int $size): void { $this->barWidth = max(1, $size); } @@ -225,7 +246,7 @@ final class ProgressBar return $this->barWidth; } - public function setBarCharacter(string $char) + public function setBarCharacter(string $char): void { $this->barChar = $char; } @@ -235,7 +256,7 @@ final class ProgressBar return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar); } - public function setEmptyBarCharacter(string $char) + public function setEmptyBarCharacter(string $char): void { $this->emptyBarChar = $char; } @@ -245,7 +266,7 @@ final class ProgressBar return $this->emptyBarChar; } - public function setProgressCharacter(string $char) + public function setProgressCharacter(string $char): void { $this->progressChar = $char; } @@ -255,7 +276,7 @@ final class ProgressBar return $this->progressChar; } - public function setFormat(string $format) + public function setFormat(string $format): void { $this->format = null; $this->internalFormat = $format; @@ -266,7 +287,7 @@ final class ProgressBar * * @param int|null $freq The frequency in steps */ - public function setRedrawFrequency(?int $freq) + public function setRedrawFrequency(?int $freq): void { $this->redrawFreq = null !== $freq ? max(1, $freq) : null; } @@ -325,7 +346,7 @@ final class ProgressBar * * @param int $step Number of steps to advance */ - public function advance(int $step = 1) + public function advance(int $step = 1): void { $this->setProgress($this->step + $step); } @@ -333,12 +354,12 @@ final class ProgressBar /** * Sets whether to overwrite the progressbar, false for new line. */ - public function setOverwrite(bool $overwrite) + public function setOverwrite(bool $overwrite): void { $this->overwrite = $overwrite; } - public function setProgress(int $step) + public function setProgress(int $step): void { if ($this->max && $step > $this->max) { $this->max = $step; @@ -371,7 +392,7 @@ final class ProgressBar } } - public function setMaxSteps(int $max) + public function setMaxSteps(int $max): void { $this->format = null; $this->max = max(0, $max); @@ -431,7 +452,7 @@ final class ProgressBar $this->overwrite(''); } - private function setRealFormat(string $format) + private function setRealFormat(string $format): void { // try to use the _nomax variant if available if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) { @@ -513,9 +534,7 @@ final class ProgressBar return $display; }, - 'elapsed' => function (self $bar) { - return Helper::formatTime(time() - $bar->getStartTime()); - }, + 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime()), 'remaining' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); @@ -530,18 +549,10 @@ final class ProgressBar return Helper::formatTime($bar->getEstimated()); }, - 'memory' => function (self $bar) { - return Helper::formatMemory(memory_get_usage(true)); - }, - 'current' => function (self $bar) { - return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT); - }, - 'max' => function (self $bar) { - return $bar->getMaxSteps(); - }, - 'percent' => function (self $bar) { - return floor($bar->getProgressPercent() * 100); - }, + 'memory' => fn (self $bar) => Helper::formatMemory(memory_get_usage(true)), + 'current' => fn (self $bar) => str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT), + 'max' => fn (self $bar) => $bar->getMaxSteps(), + 'percent' => fn (self $bar) => floor($bar->getProgressPercent() * 100), ]; } @@ -568,7 +579,7 @@ final class ProgressBar $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; $callback = function ($matches) { - if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { + if ($formatter = $this->getPlaceholderFormatter($matches[1])) { $text = $formatter($this, $this->output); } elseif (isset($this->messages[$matches[1]])) { $text = $this->messages[$matches[1]]; @@ -585,9 +596,7 @@ final class ProgressBar $line = preg_replace_callback($regex, $callback, $this->format); // gets string length for each sub line with multiline format - $linesLength = array_map(function ($subLine) { - return Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r"))); - }, explode("\n", $line)); + $linesLength = array_map(fn ($subLine) => Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r"))), explode("\n", $line)); $linesWidth = max($linesLength); diff --git a/vendor/symfony/console/Helper/ProgressIndicator.php b/vendor/symfony/console/Helper/ProgressIndicator.php index b5fa24c4..84dbef95 100644 --- a/vendor/symfony/console/Helper/ProgressIndicator.php +++ b/vendor/symfony/console/Helper/ProgressIndicator.php @@ -70,6 +70,8 @@ class ProgressIndicator /** * Sets the current indicator message. + * + * @return void */ public function setMessage(?string $message) { @@ -80,6 +82,8 @@ class ProgressIndicator /** * Starts the indicator output. + * + * @return void */ public function start(string $message) { @@ -98,6 +102,8 @@ class ProgressIndicator /** * Advances the indicator. + * + * @return void */ public function advance() { @@ -123,6 +129,8 @@ class ProgressIndicator /** * Finish the indicator with message. + * + * @return void */ public function finish(string $message) { @@ -148,6 +156,8 @@ class ProgressIndicator * Sets a placeholder formatter for a given name. * * This method also allow you to override an existing placeholder. + * + * @return void */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable) { @@ -166,7 +176,7 @@ class ProgressIndicator return self::$formatters[$name] ?? null; } - private function display() + private function display(): void { if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { return; @@ -195,7 +205,7 @@ class ProgressIndicator /** * Overwrites a previous message to the output. */ - private function overwrite(string $message) + private function overwrite(string $message): void { if ($this->output->isDecorated()) { $this->output->write("\x0D\x1B[2K"); @@ -216,18 +226,10 @@ class ProgressIndicator private static function initPlaceholderFormatters(): array { return [ - 'indicator' => function (self $indicator) { - return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)]; - }, - 'message' => function (self $indicator) { - return $indicator->message; - }, - 'elapsed' => function (self $indicator) { - return Helper::formatTime(time() - $indicator->startTime); - }, - 'memory' => function () { - return Helper::formatMemory(memory_get_usage(true)); - }, + 'indicator' => fn (self $indicator) => $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)], + 'message' => fn (self $indicator) => $indicator->message, + 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime), + 'memory' => fn () => Helper::formatMemory(memory_get_usage(true)), ]; } } diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php index c345b4af..f32813c6 100644 --- a/vendor/symfony/console/Helper/QuestionHelper.php +++ b/vendor/symfony/console/Helper/QuestionHelper.php @@ -68,9 +68,7 @@ class QuestionHelper extends Helper return $this->doAsk($output, $question); } - $interviewer = function () use ($output, $question) { - return $this->doAsk($output, $question); - }; + $interviewer = fn () => $this->doAsk($output, $question); return $this->validateAttempts($interviewer, $output, $question); } catch (MissingInputException $exception) { @@ -91,6 +89,8 @@ class QuestionHelper extends Helper /** * Prevents usage of stty. + * + * @return void */ public static function disableStty() { @@ -123,7 +123,18 @@ class QuestionHelper extends Helper } if (false === $ret) { + $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true; + + if (!$isBlocked) { + stream_set_blocking($inputStream, true); + } + $ret = $this->readInput($inputStream, $question); + + if (!$isBlocked) { + stream_set_blocking($inputStream, false); + } + if (false === $ret) { throw new MissingInputException('Aborted.'); } @@ -159,7 +170,7 @@ class QuestionHelper extends Helper } if ($validator = $question->getValidator()) { - return \call_user_func($question->getValidator(), $default); + return \call_user_func($validator, $default); } elseif ($question instanceof ChoiceQuestion) { $choices = $question->getChoices(); @@ -179,6 +190,8 @@ class QuestionHelper extends Helper /** * Outputs the question prompt. + * + * @return void */ protected function writePrompt(OutputInterface $output, Question $question) { @@ -215,6 +228,8 @@ class QuestionHelper extends Helper /** * Outputs an error message. + * + * @return void */ protected function writeError(OutputInterface $output, \Exception $error) { @@ -314,9 +329,7 @@ class QuestionHelper extends Helper $matches = array_filter( $autocomplete($ret), - function ($match) use ($ret) { - return '' === $ret || str_starts_with($match, $ret); - } + fn ($match) => '' === $ret || str_starts_with($match, $ret) ); $numMatches = \count($matches); $ofs = -1; @@ -496,13 +509,11 @@ class QuestionHelper extends Helper return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); } - if (!\function_exists('exec')) { + if (!\function_exists('shell_exec')) { return self::$stdinIsInteractive = true; } - exec('stty 2> /dev/null', $output, $status); - - return self::$stdinIsInteractive = 1 !== $status; + return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } /** diff --git a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php index 109045d0..8ebc8437 100644 --- a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php +++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php @@ -25,6 +25,9 @@ use Symfony\Component\Console\Style\SymfonyStyle; */ class SymfonyQuestionHelper extends QuestionHelper { + /** + * @return void + */ protected function writePrompt(OutputInterface $output, Question $question) { $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); @@ -80,6 +83,9 @@ class SymfonyQuestionHelper extends QuestionHelper $output->write($prompt); } + /** + * @return void + */ protected function writeError(OutputInterface $output, \Exception $error) { if ($output instanceof SymfonyStyle) { diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php index 893b3192..cf714873 100644 --- a/vendor/symfony/console/Helper/Table.php +++ b/vendor/symfony/console/Helper/Table.php @@ -66,6 +66,8 @@ class Table /** * Sets a style definition. + * + * @return void */ public static function setStyleDefinition(string $name, TableStyle $style) { @@ -310,6 +312,8 @@ class Table * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | * +---------------+-----------------------+------------------+ + * + * @return void */ public function render() { @@ -450,7 +454,7 @@ class Table * * +-----+-----------+-------+ */ - private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null) + private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null): void { if (!$count = $this->numberOfColumns) { return; @@ -515,7 +519,7 @@ class Table * * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | */ - private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null) + private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null): void { $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); $columns = $this->getRowColumns($row); @@ -588,7 +592,7 @@ class Table /** * Calculate number of columns for this table. */ - private function calculateNumberOfColumns(array $rows) + private function calculateNumberOfColumns(array $rows): void { $columns = [0]; foreach ($rows as $row) { @@ -727,7 +731,7 @@ class Table /** * fill cells for a row that contains colspan > 1. */ - private function fillCells(iterable $row) + private function fillCells(iterable $row): iterable { $newRow = []; @@ -789,7 +793,7 @@ class Table /** * Calculates columns widths. */ - private function calculateColumnsWidth(iterable $groups) + private function calculateColumnsWidth(iterable $groups): void { for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = []; @@ -804,7 +808,7 @@ class Table $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); $textLength = Helper::width($textContent); if ($textLength > 0) { - $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan())); + $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { $row[$i + $position] = $content; } @@ -843,7 +847,7 @@ class Table /** * Called after rendering to cleanup cache data. */ - private function cleanup() + private function cleanup(): void { $this->effectiveColumnWidths = []; unset($this->numberOfColumns); diff --git a/vendor/symfony/console/Helper/TableCellStyle.php b/vendor/symfony/console/Helper/TableCellStyle.php index 65ae9e72..9419dcb4 100644 --- a/vendor/symfony/console/Helper/TableCellStyle.php +++ b/vendor/symfony/console/Helper/TableCellStyle.php @@ -67,9 +67,7 @@ class TableCellStyle { return array_filter( $this->getOptions(), - function ($key) { - return \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]); - }, + fn ($key) => \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]), \ARRAY_FILTER_USE_KEY ); } diff --git a/vendor/symfony/console/Input/ArgvInput.php b/vendor/symfony/console/Input/ArgvInput.php index c0c28bb5..59f9217e 100644 --- a/vendor/symfony/console/Input/ArgvInput.php +++ b/vendor/symfony/console/Input/ArgvInput.php @@ -55,11 +55,17 @@ class ArgvInput extends Input parent::__construct($definition); } + /** + * @return void + */ protected function setTokens(array $tokens) { $this->tokens = $tokens; } + /** + * @return void + */ protected function parse() { $parseOptions = true; @@ -89,7 +95,7 @@ class ArgvInput extends Input /** * Parses a short option. */ - private function parseShortOption(string $token) + private function parseShortOption(string $token): void { $name = substr($token, 1); @@ -110,7 +116,7 @@ class ArgvInput extends Input * * @throws RuntimeException When option given doesn't exist */ - private function parseShortOptionSet(string $name) + private function parseShortOptionSet(string $name): void { $len = \strlen($name); for ($i = 0; $i < $len; ++$i) { @@ -133,7 +139,7 @@ class ArgvInput extends Input /** * Parses a long option. */ - private function parseLongOption(string $token) + private function parseLongOption(string $token): void { $name = substr($token, 2); @@ -152,7 +158,7 @@ class ArgvInput extends Input * * @throws RuntimeException When too many arguments are given */ - private function parseArgument(string $token) + private function parseArgument(string $token): void { $c = \count($this->arguments); @@ -196,7 +202,7 @@ class ArgvInput extends Input * * @throws RuntimeException When option given doesn't exist */ - private function addShortOption(string $shortcut, mixed $value) + private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); @@ -210,7 +216,7 @@ class ArgvInput extends Input * * @throws RuntimeException When option given doesn't exist */ - private function addLongOption(string $name, mixed $value) + private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { diff --git a/vendor/symfony/console/Input/ArrayInput.php b/vendor/symfony/console/Input/ArrayInput.php index 02fb4e8e..355de61d 100644 --- a/vendor/symfony/console/Input/ArrayInput.php +++ b/vendor/symfony/console/Input/ArrayInput.php @@ -113,6 +113,9 @@ class ArrayInput extends Input return implode(' ', $params); } + /** + * @return void + */ protected function parse() { foreach ($this->parameters as $key => $value) { @@ -134,7 +137,7 @@ class ArrayInput extends Input * * @throws InvalidOptionException When option given doesn't exist */ - private function addShortOption(string $shortcut, mixed $value) + private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut)); @@ -149,7 +152,7 @@ class ArrayInput extends Input * @throws InvalidOptionException When option given doesn't exist * @throws InvalidOptionException When a required value is missing */ - private function addLongOption(string $name, mixed $value) + private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { @@ -182,7 +185,7 @@ class ArrayInput extends Input * * @throws InvalidArgumentException When argument given doesn't exist */ - private function addArgument(string|int $name, mixed $value) + 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)); diff --git a/vendor/symfony/console/Input/Input.php b/vendor/symfony/console/Input/Input.php index 7b90713c..0f5617cd 100644 --- a/vendor/symfony/console/Input/Input.php +++ b/vendor/symfony/console/Input/Input.php @@ -43,6 +43,9 @@ abstract class Input implements InputInterface, StreamableInputInterface } } + /** + * @return void + */ public function bind(InputDefinition $definition) { $this->arguments = []; @@ -54,17 +57,20 @@ abstract class Input implements InputInterface, StreamableInputInterface /** * Processes command line arguments. + * + * @return void */ abstract protected function parse(); + /** + * @return void + */ public function validate() { $definition = $this->definition; $givenArguments = $this->arguments; - $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) { - return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); - }); + $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))); @@ -76,6 +82,9 @@ abstract class Input implements InputInterface, StreamableInputInterface return $this->interactive; } + /** + * @return void + */ public function setInteractive(bool $interactive) { $this->interactive = $interactive; @@ -95,6 +104,9 @@ abstract class Input implements InputInterface, StreamableInputInterface return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); } + /** + * @return void + */ public function setArgument(string $name, mixed $value) { if (!$this->definition->hasArgument($name)) { @@ -131,6 +143,9 @@ abstract class Input implements InputInterface, StreamableInputInterface return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } + /** + * @return void + */ public function setOption(string $name, mixed $value) { if ($this->definition->hasNegation($name)) { @@ -157,11 +172,19 @@ abstract class Input implements InputInterface, StreamableInputInterface return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token); } + /** + * @param resource $stream + * + * @return void + */ public function setStream($stream) { $this->stream = $stream; } + /** + * @return resource + */ public function getStream() { return $this->stream; diff --git a/vendor/symfony/console/Input/InputArgument.php b/vendor/symfony/console/Input/InputArgument.php index a130c412..5cb15148 100644 --- a/vendor/symfony/console/Input/InputArgument.php +++ b/vendor/symfony/console/Input/InputArgument.php @@ -37,7 +37,7 @@ class InputArgument /** * @param string $name The argument name - * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY * @param string $description A description text * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion @@ -91,6 +91,8 @@ class InputArgument /** * Sets the default value. * + * @return void + * * @throws LogicException When incorrect default value is given */ public function setDefault(string|bool|int|float|array $default = null) diff --git a/vendor/symfony/console/Input/InputAwareInterface.php b/vendor/symfony/console/Input/InputAwareInterface.php index 5a288de5..0ad27b45 100644 --- a/vendor/symfony/console/Input/InputAwareInterface.php +++ b/vendor/symfony/console/Input/InputAwareInterface.php @@ -21,6 +21,8 @@ interface InputAwareInterface { /** * Sets the Console Input. + * + * @return void */ public function setInput(InputInterface $input); } diff --git a/vendor/symfony/console/Input/InputDefinition.php b/vendor/symfony/console/Input/InputDefinition.php index f4b14a1c..b7162d77 100644 --- a/vendor/symfony/console/Input/InputDefinition.php +++ b/vendor/symfony/console/Input/InputDefinition.php @@ -46,6 +46,8 @@ class InputDefinition /** * Sets the definition of the input. + * + * @return void */ public function setDefinition(array $definition) { @@ -67,6 +69,8 @@ class InputDefinition * Sets the InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void */ public function setArguments(array $arguments = []) { @@ -81,6 +85,8 @@ class InputDefinition * Adds an array of InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void */ public function addArguments(?array $arguments = []) { @@ -92,6 +98,8 @@ class InputDefinition } /** + * @return void + * * @throws LogicException When incorrect argument is given */ public function addArgument(InputArgument $argument) @@ -190,6 +198,8 @@ class InputDefinition * Sets the InputOption objects. * * @param InputOption[] $options An array of InputOption objects + * + * @return void */ public function setOptions(array $options = []) { @@ -203,6 +213,8 @@ class InputDefinition * Adds an array of InputOption objects. * * @param InputOption[] $options An array of InputOption objects + * + * @return void */ public function addOptions(array $options = []) { @@ -212,6 +224,8 @@ class InputDefinition } /** + * @return void + * * @throws LogicException When option given already exist */ public function addOption(InputOption $option) diff --git a/vendor/symfony/console/Input/InputInterface.php b/vendor/symfony/console/Input/InputInterface.php index 3af991a7..aaed5fd0 100644 --- a/vendor/symfony/console/Input/InputInterface.php +++ b/vendor/symfony/console/Input/InputInterface.php @@ -61,6 +61,8 @@ interface InputInterface /** * Binds the current Input instance with the given arguments and options. * + * @return void + * * @throws RuntimeException */ public function bind(InputDefinition $definition); @@ -68,6 +70,8 @@ interface InputInterface /** * Validates the input. * + * @return void + * * @throws RuntimeException When not enough arguments are given */ public function validate(); @@ -91,6 +95,8 @@ interface InputInterface /** * Sets an argument value by name. * + * @return void + * * @throws InvalidArgumentException When argument given doesn't exist */ public function setArgument(string $name, mixed $value); @@ -119,6 +125,8 @@ interface InputInterface /** * Sets an option value by name. * + * @return void + * * @throws InvalidArgumentException When option given doesn't exist */ public function setOption(string $name, mixed $value); @@ -135,6 +143,8 @@ interface InputInterface /** * Sets the input interactivity. + * + * @return void */ public function setInteractive(bool $interactive); } diff --git a/vendor/symfony/console/Input/InputOption.php b/vendor/symfony/console/Input/InputOption.php index 9a7032a0..fdf88dcc 100644 --- a/vendor/symfony/console/Input/InputOption.php +++ b/vendor/symfony/console/Input/InputOption.php @@ -178,6 +178,9 @@ class InputOption return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); } + /** + * @return void + */ public function setDefault(string|bool|int|float|array $default = null) { if (1 > \func_num_args()) { diff --git a/vendor/symfony/console/Input/StreamableInputInterface.php b/vendor/symfony/console/Input/StreamableInputInterface.php index d7e462f2..4b95fcb1 100644 --- a/vendor/symfony/console/Input/StreamableInputInterface.php +++ b/vendor/symfony/console/Input/StreamableInputInterface.php @@ -25,6 +25,8 @@ interface StreamableInputInterface extends InputInterface * This is mainly useful for testing purpose. * * @param resource $stream The input stream + * + * @return void */ public function setStream($stream); diff --git a/vendor/symfony/console/Output/AnsiColorMode.php b/vendor/symfony/console/Output/AnsiColorMode.php index c6cc5c12..5f9f744f 100644 --- a/vendor/symfony/console/Output/AnsiColorMode.php +++ b/vendor/symfony/console/Output/AnsiColorMode.php @@ -26,7 +26,7 @@ enum AnsiColorMode case Ansi4; /* - * 8-bit Ansi colors (240 differents colors + 16 duplicate color codes, ensuring backward compatibility). + * 8-bit Ansi colors (240 different colors + 16 duplicate color codes, ensuring backward compatibility). * Output syntax is: "ESC[38;5;${foreGroundColorcode};48;5;${backGroundColorcode}m" * Should be compatible with most terminals. */ @@ -78,25 +78,7 @@ enum AnsiColorMode private function degradeHexColorToAnsi4(int $r, int $g, int $b): int { - if (0 === round($this->getSaturation($r, $g, $b) / 50)) { - return 0; - } - - return (int) ((round($b / 255) << 2) | (round($g / 255) << 1) | round($r / 255)); - } - - private function getSaturation(int $r, int $g, int $b): int - { - $r = $r / 255; - $g = $g / 255; - $b = $b / 255; - $v = max($r, $g, $b); - - if (0 === $diff = $v - min($r, $g, $b)) { - return 0; - } - - return (int) ((int) $diff * 100 / $v); + return round($b / 255) << 2 | (round($g / 255) << 1) | round($r / 255); } /** diff --git a/vendor/symfony/console/Output/BufferedOutput.php b/vendor/symfony/console/Output/BufferedOutput.php index 94d4e414..ef5099bf 100644 --- a/vendor/symfony/console/Output/BufferedOutput.php +++ b/vendor/symfony/console/Output/BufferedOutput.php @@ -29,6 +29,9 @@ class BufferedOutput extends Output return $content; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; diff --git a/vendor/symfony/console/Output/ConsoleOutput.php b/vendor/symfony/console/Output/ConsoleOutput.php index e3aa92c7..c1eb7cd1 100644 --- a/vendor/symfony/console/Output/ConsoleOutput.php +++ b/vendor/symfony/console/Output/ConsoleOutput.php @@ -64,18 +64,27 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); } + /** + * @return void + */ public function setDecorated(bool $decorated) { parent::setDecorated($decorated); $this->stderr->setDecorated($decorated); } + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { parent::setFormatter($formatter); $this->stderr->setFormatter($formatter); } + /** + * @return void + */ public function setVerbosity(int $level) { parent::setVerbosity($level); @@ -87,6 +96,9 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface return $this->stderr; } + /** + * @return void + */ public function setErrorOutput(OutputInterface $error) { $this->stderr = $error; diff --git a/vendor/symfony/console/Output/ConsoleOutputInterface.php b/vendor/symfony/console/Output/ConsoleOutputInterface.php index 6b4babc6..9c0049c8 100644 --- a/vendor/symfony/console/Output/ConsoleOutputInterface.php +++ b/vendor/symfony/console/Output/ConsoleOutputInterface.php @@ -24,6 +24,9 @@ interface ConsoleOutputInterface extends OutputInterface */ public function getErrorOutput(): OutputInterface; + /** + * @return void + */ public function setErrorOutput(OutputInterface $error); public function section(): ConsoleSectionOutput; diff --git a/vendor/symfony/console/Output/ConsoleSectionOutput.php b/vendor/symfony/console/Output/ConsoleSectionOutput.php index c813c811..3f3f1434 100644 --- a/vendor/symfony/console/Output/ConsoleSectionOutput.php +++ b/vendor/symfony/console/Output/ConsoleSectionOutput.php @@ -60,6 +60,8 @@ class ConsoleSectionOutput extends StreamOutput * Clears previous output for this section. * * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared + * + * @return void */ public function clear(int $lines = null) { @@ -81,6 +83,8 @@ class ConsoleSectionOutput extends StreamOutput /** * Overwrites the previous output with a new message. + * + * @return void */ public function overwrite(string|iterable $message) { @@ -153,12 +157,15 @@ class ConsoleSectionOutput extends StreamOutput /** * @internal */ - public function addNewLineOfInputSubmit() + public function addNewLineOfInputSubmit(): void { $this->content[] = \PHP_EOL; ++$this->lines; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { if (!$this->isDecorated()) { diff --git a/vendor/symfony/console/Output/NullOutput.php b/vendor/symfony/console/Output/NullOutput.php index 4884cbad..f3aa15b1 100644 --- a/vendor/symfony/console/Output/NullOutput.php +++ b/vendor/symfony/console/Output/NullOutput.php @@ -26,6 +26,9 @@ class NullOutput implements OutputInterface { private NullOutputFormatter $formatter; + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { // do nothing @@ -37,6 +40,9 @@ class NullOutput implements OutputInterface return $this->formatter ??= new NullOutputFormatter(); } + /** + * @return void + */ public function setDecorated(bool $decorated) { // do nothing @@ -47,6 +53,9 @@ class NullOutput implements OutputInterface return false; } + /** + * @return void + */ public function setVerbosity(int $level) { // do nothing @@ -77,11 +86,17 @@ class NullOutput implements OutputInterface return false; } + /** + * @return void + */ public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) { // do nothing } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) { // do nothing diff --git a/vendor/symfony/console/Output/Output.php b/vendor/symfony/console/Output/Output.php index 4cb71acb..3a06311a 100644 --- a/vendor/symfony/console/Output/Output.php +++ b/vendor/symfony/console/Output/Output.php @@ -44,6 +44,9 @@ abstract class Output implements OutputInterface $this->formatter->setDecorated($decorated); } + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { $this->formatter = $formatter; @@ -54,6 +57,9 @@ abstract class Output implements OutputInterface return $this->formatter; } + /** + * @return void + */ public function setDecorated(bool $decorated) { $this->formatter->setDecorated($decorated); @@ -64,6 +70,9 @@ abstract class Output implements OutputInterface return $this->formatter->isDecorated(); } + /** + * @return void + */ public function setVerbosity(int $level) { $this->verbosity = $level; @@ -94,11 +103,17 @@ abstract class Output implements OutputInterface return self::VERBOSITY_DEBUG <= $this->verbosity; } + /** + * @return void + */ public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) { $this->write($messages, true, $options); } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { @@ -133,6 +148,8 @@ abstract class Output implements OutputInterface /** * Writes a message to the output. + * + * @return void */ abstract protected function doWrite(string $message, bool $newline); } diff --git a/vendor/symfony/console/Output/OutputInterface.php b/vendor/symfony/console/Output/OutputInterface.php index bc927c51..fb155772 100644 --- a/vendor/symfony/console/Output/OutputInterface.php +++ b/vendor/symfony/console/Output/OutputInterface.php @@ -36,6 +36,8 @@ interface OutputInterface * @param bool $newline Whether to add a newline * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void */ public function write(string|iterable $messages, bool $newline = false, int $options = 0); @@ -44,11 +46,15 @@ interface OutputInterface * * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void */ public function writeln(string|iterable $messages, int $options = 0); /** * Sets the verbosity of the output. + * + * @return void */ public function setVerbosity(int $level); @@ -79,6 +85,8 @@ interface OutputInterface /** * Sets the decorated flag. + * + * @return void */ public function setDecorated(bool $decorated); @@ -87,6 +95,9 @@ interface OutputInterface */ public function isDecorated(): bool; + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter); /** diff --git a/vendor/symfony/console/Output/StreamOutput.php b/vendor/symfony/console/Output/StreamOutput.php index 9ec524e4..155066ea 100644 --- a/vendor/symfony/console/Output/StreamOutput.php +++ b/vendor/symfony/console/Output/StreamOutput.php @@ -62,6 +62,9 @@ class StreamOutput extends Output return $this->stream; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { if ($newline) { diff --git a/vendor/symfony/console/Output/TrimmedBufferOutput.php b/vendor/symfony/console/Output/TrimmedBufferOutput.php index 1ca5a13e..b00445ec 100644 --- a/vendor/symfony/console/Output/TrimmedBufferOutput.php +++ b/vendor/symfony/console/Output/TrimmedBufferOutput.php @@ -45,6 +45,9 @@ class TrimmedBufferOutput extends Output return $content; } + /** + * @return void + */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; diff --git a/vendor/symfony/console/Question/Question.php b/vendor/symfony/console/Question/Question.php index b06db945..26896bb5 100644 --- a/vendor/symfony/console/Question/Question.php +++ b/vendor/symfony/console/Question/Question.php @@ -146,12 +146,11 @@ class Question if (\is_array($values)) { $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values); - $callback = static function () use ($values) { - return $values; - }; + $callback = static fn () => $values; } elseif ($values instanceof \Traversable) { - $valueCache = null; - $callback = static function () use ($values, &$valueCache) { + $callback = static function () use ($values) { + static $valueCache; + return $valueCache ??= iterator_to_array($values, false); }; } else { @@ -267,6 +266,9 @@ class Question return $this->normalizer; } + /** + * @return bool + */ protected function isAssoc(array $array) { return (bool) \count(array_filter(array_keys($array), 'is_string')); diff --git a/vendor/symfony/console/README.md b/vendor/symfony/console/README.md index c89b4a1a..bfd48810 100644 --- a/vendor/symfony/console/README.md +++ b/vendor/symfony/console/README.md @@ -4,6 +4,18 @@ Console Component The Console component eases the creation of beautiful and testable command line interfaces. +Sponsor +------- + +The Console component for Symfony 6.3 is [backed][1] by [Les-Tilleuls.coop][2]. + +Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and +fix your projects. They provide a wide range of professional services including development, +consulting, coaching, training and audits. They also are highly skilled in JS, Go and DevOps. +They are a worker cooperative! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -18,3 +30,7 @@ Credits `Resources/bin/hiddeninput.exe` is a third party binary provided within this component. Find sources and license at https://github.com/Seldaek/hidden-input. + +[1]: https://symfony.com/backers +[2]: https://les-tilleuls.coop +[3]: https://symfony.com/sponsor diff --git a/vendor/symfony/console/Resources/completion.bash b/vendor/symfony/console/Resources/completion.bash index ad69eab0..0d76eacc 100644 --- a/vendor/symfony/console/Resources/completion.bash +++ b/vendor/symfony/console/Resources/completion.bash @@ -6,6 +6,16 @@ # https://symfony.com/doc/current/contributing/code/license.html _sf_{{ COMMAND_NAME }}() { + + # Use the default completion for shell redirect operators. + for w in '>' '>>' '&>' '<'; do + if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then + compopt -o filenames + COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")) + return 0 + fi + done + # Use newline as only separator to allow space in completion values IFS=$'\n' local sf_cmd="${COMP_WORDS[0]}" diff --git a/vendor/symfony/console/Resources/completion.zsh b/vendor/symfony/console/Resources/completion.zsh index 97a9e88c..ff76fe5f 100644 --- a/vendor/symfony/console/Resources/completion.zsh +++ b/vendor/symfony/console/Resources/completion.zsh @@ -1,3 +1,5 @@ +#compdef {{ COMMAND_NAME }} + # This file is part of the Symfony package. # # (c) Fabien Potencier diff --git a/vendor/symfony/console/Style/OutputStyle.php b/vendor/symfony/console/Style/OutputStyle.php index b694bb53..ddfa8dec 100644 --- a/vendor/symfony/console/Style/OutputStyle.php +++ b/vendor/symfony/console/Style/OutputStyle.php @@ -30,6 +30,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface $this->output = $output; } + /** + * @return void + */ public function newLine(int $count = 1) { $this->output->write(str_repeat(\PHP_EOL, $count)); @@ -40,16 +43,25 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return new ProgressBar($this->output, $max); } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) { $this->output->write($messages, $newline, $type); } + /** + * @return void + */ public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) { $this->output->writeln($messages, $type); } + /** + * @return void + */ public function setVerbosity(int $level) { $this->output->setVerbosity($level); @@ -60,6 +72,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return $this->output->getVerbosity(); } + /** + * @return void + */ public function setDecorated(bool $decorated) { $this->output->setDecorated($decorated); @@ -70,6 +85,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return $this->output->isDecorated(); } + /** + * @return void + */ public function setFormatter(OutputFormatterInterface $formatter) { $this->output->setFormatter($formatter); @@ -100,6 +118,9 @@ abstract class OutputStyle implements OutputInterface, StyleInterface return $this->output->isDebug(); } + /** + * @return OutputInterface + */ protected function getErrorOutput() { if (!$this->output instanceof ConsoleOutputInterface) { diff --git a/vendor/symfony/console/Style/StyleInterface.php b/vendor/symfony/console/Style/StyleInterface.php index 0bb12339..e25a65bd 100644 --- a/vendor/symfony/console/Style/StyleInterface.php +++ b/vendor/symfony/console/Style/StyleInterface.php @@ -20,51 +20,71 @@ interface StyleInterface { /** * Formats a command title. + * + * @return void */ public function title(string $message); /** * Formats a section title. + * + * @return void */ public function section(string $message); /** * Formats a list. + * + * @return void */ public function listing(array $elements); /** * Formats informational text. + * + * @return void */ public function text(string|array $message); /** * Formats a success result bar. + * + * @return void */ public function success(string|array $message); /** * Formats an error result bar. + * + * @return void */ public function error(string|array $message); /** * Formats an warning result bar. + * + * @return void */ public function warning(string|array $message); /** * Formats a note admonition. + * + * @return void */ public function note(string|array $message); /** * Formats a caution admonition. + * + * @return void */ public function caution(string|array $message); /** * Formats a table. + * + * @return void */ public function table(array $headers, array $rows); @@ -90,21 +110,29 @@ interface StyleInterface /** * Add newline(s). + * + * @return void */ public function newLine(int $count = 1); /** * Starts the progress output. + * + * @return void */ public function progressStart(int $max = 0); /** * Advances the progress output X steps. + * + * @return void */ public function progressAdvance(int $step = 1); /** * Finishes the progress output. + * + * @return void */ public function progressFinish(); } diff --git a/vendor/symfony/console/Style/SymfonyStyle.php b/vendor/symfony/console/Style/SymfonyStyle.php index 8fd6f849..cecce6c0 100644 --- a/vendor/symfony/console/Style/SymfonyStyle.php +++ b/vendor/symfony/console/Style/SymfonyStyle.php @@ -60,6 +60,8 @@ class SymfonyStyle extends OutputStyle /** * Formats a message as a block of text. + * + * @return void */ public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) { @@ -70,6 +72,9 @@ class SymfonyStyle extends OutputStyle $this->newLine(); } + /** + * @return void + */ public function title(string $message) { $this->autoPrependBlock(); @@ -80,6 +85,9 @@ class SymfonyStyle extends OutputStyle $this->newLine(); } + /** + * @return void + */ public function section(string $message) { $this->autoPrependBlock(); @@ -90,17 +98,21 @@ class SymfonyStyle extends OutputStyle $this->newLine(); } + /** + * @return void + */ public function listing(array $elements) { $this->autoPrependText(); - $elements = array_map(function ($element) { - return sprintf(' * %s', $element); - }, $elements); + $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); $this->writeln($elements); $this->newLine(); } + /** + * @return void + */ public function text(string|array $message) { $this->autoPrependText(); @@ -113,27 +125,41 @@ class SymfonyStyle extends OutputStyle /** * Formats a command comment. + * + * @return void */ public function comment(string|array $message) { $this->block($message, null, null, ' // ', false, false); } + /** + * @return void + */ public function success(string|array $message) { $this->block($message, 'OK', 'fg=black;bg=green', ' ', true); } + /** + * @return void + */ public function error(string|array $message) { $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true); } + /** + * @return void + */ public function warning(string|array $message) { $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true); } + /** + * @return void + */ public function note(string|array $message) { $this->block($message, 'NOTE', 'fg=yellow', ' ! '); @@ -141,17 +167,25 @@ class SymfonyStyle extends OutputStyle /** * Formats an info message. + * + * @return void */ public function info(string|array $message) { $this->block($message, 'INFO', 'fg=green', ' ', true); } + /** + * @return void + */ public function caution(string|array $message) { $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true); } + /** + * @return void + */ public function table(array $headers, array $rows) { $this->createTable() @@ -165,6 +199,8 @@ class SymfonyStyle extends OutputStyle /** * Formats a horizontal table. + * + * @return void */ public function horizontalTable(array $headers, array $rows) { @@ -185,6 +221,8 @@ class SymfonyStyle extends OutputStyle * * 'A title' * * ['key' => 'value'] * * new TableSeparator() + * + * @return void */ public function definitionList(string|array|TableSeparator ...$list) { @@ -247,17 +285,26 @@ class SymfonyStyle extends OutputStyle return $this->askQuestion($questionChoice); } + /** + * @return void + */ public function progressStart(int $max = 0) { $this->progressBar = $this->createProgressBar($max); $this->progressBar->start(); } + /** + * @return void + */ public function progressAdvance(int $step = 1) { $this->getProgressBar()->advance($step); } + /** + * @return void + */ public function progressFinish() { $this->getProgressBar()->finish(); @@ -311,6 +358,9 @@ class SymfonyStyle extends OutputStyle return $answer; } + /** + * @return void + */ public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { @@ -323,6 +373,9 @@ class SymfonyStyle extends OutputStyle } } + /** + * @return void + */ public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { @@ -335,6 +388,9 @@ class SymfonyStyle extends OutputStyle } } + /** + * @return void + */ public function newLine(int $count = 1) { parent::newLine($count); @@ -381,7 +437,7 @@ class SymfonyStyle extends OutputStyle { $fetched = $this->bufferedOutput->fetch(); // Prepend new line if last char isn't EOL: - if (!str_ends_with($fetched, "\n")) { + if ($fetched && !str_ends_with($fetched, "\n")) { $this->newLine(); } } diff --git a/vendor/symfony/console/Terminal.php b/vendor/symfony/console/Terminal.php index 216c609f..3eda0376 100644 --- a/vendor/symfony/console/Terminal.php +++ b/vendor/symfony/console/Terminal.php @@ -123,20 +123,19 @@ class Terminal return self::$stty; } - // skip check if exec function is disabled - if (!\function_exists('exec')) { + // skip check if shell_exec function is disabled + if (!\function_exists('shell_exec')) { return false; } - exec('stty 2>&1', $output, $exitcode); - - return self::$stty = 0 === $exitcode; + return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } - private static function initDimensions() + private static function initDimensions(): void { if ('\\' === \DIRECTORY_SEPARATOR) { - if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) { + $ansicon = getenv('ANSICON'); + if (false !== $ansicon && preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim($ansicon), $matches)) { // extract [w, H] from "wxh (WxH)" // or [w, h] from "wxh" self::$width = (int) $matches[1]; @@ -166,7 +165,7 @@ class Terminal /** * Initializes dimensions using the output of an stty columns line. */ - private static function initDimensionsUsingStty() + private static function initDimensionsUsingStty(): void { if ($sttyString = self::getSttyColumns()) { if (preg_match('/rows.(\d+);.columns.(\d+);/is', $sttyString, $matches)) { @@ -216,6 +215,8 @@ class Terminal 2 => ['pipe', 'w'], ]; + $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)) { return null; @@ -226,6 +227,10 @@ class Terminal fclose($pipes[2]); proc_close($process); + if ($cp) { + sapi_windows_cp_set($cp); + } + return $info; } } diff --git a/vendor/symfony/console/Tester/TesterTrait.php b/vendor/symfony/console/Tester/TesterTrait.php index 9670a496..497b8c8c 100644 --- a/vendor/symfony/console/Tester/TesterTrait.php +++ b/vendor/symfony/console/Tester/TesterTrait.php @@ -128,7 +128,7 @@ trait TesterTrait * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available */ - private function initOutput(array $options) + private function initOutput(array $options): void { $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; if (!$this->captureStreamsIndependently) { diff --git a/vendor/symfony/console/composer.json b/vendor/symfony/console/composer.json index bafe5d16..c3442129 100644 --- a/vendor/symfony/console/composer.json +++ b/vendor/symfony/console/composer.json @@ -2,7 +2,7 @@ "name": "symfony/console", "type": "library", "description": "Eases the creation of beautiful and testable command line interfaces", - "keywords": ["console", "cli", "command line", "terminal"], + "keywords": ["console", "cli", "command-line", "terminal"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ @@ -17,9 +17,9 @@ ], "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "require-dev": { @@ -34,12 +34,6 @@ "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, - "suggest": { - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "", - "psr/log": "For using the console logger" - }, "conflict": { "symfony/dependency-injection": "<5.4", "symfony/dotenv": "<5.4", diff --git a/vendor/symfony/deprecation-contracts/composer.json b/vendor/symfony/deprecation-contracts/composer.json index 774200fd..c6d02d87 100644 --- a/vendor/symfony/deprecation-contracts/composer.json +++ b/vendor/symfony/deprecation-contracts/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php index 88f6a068..07d12b4a 100644 --- a/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -11,82 +11,13 @@ namespace Symfony\Contracts\Service\Test; -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; -use Symfony\Contracts\Service\ServiceLocatorTrait; +class_alias(ServiceLocatorTestCase::class, ServiceLocatorTest::class); -abstract class ServiceLocatorTest extends TestCase -{ - protected function getServiceLocator(array $factories): ContainerInterface +if (false) { + /** + * @deprecated since PHPUnit 9.6 + */ + class ServiceLocatorTest { - return new class($factories) implements ContainerInterface { - use ServiceLocatorTrait; - }; - } - - public function testHas() - { - $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - function () { return 'dummy'; }, - ]); - - $this->assertTrue($locator->has('foo')); - $this->assertTrue($locator->has('bar')); - $this->assertFalse($locator->has('dummy')); - } - - public function testGet() - { - $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('baz', $locator->get('bar')); - } - - public function testGetDoesNotMemoize() - { - $i = 0; - $locator = $this->getServiceLocator([ - 'foo' => function () use (&$i) { - ++$i; - - return 'bar'; - }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame(2, $i); - } - - public function testThrowsOnUndefinedInternalService() - { - if (!$this->getExpectedException()) { - $this->expectException(\Psr\Container\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 = $this->getServiceLocator([ - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, - ]); - - $locator->get('foo'); - } - - public function testThrowsOnCircularReference() - { - $this->expectException(\Psr\Container\ContainerExceptionInterface::class); - $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); - $locator = $this->getServiceLocator([ - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, - 'bar' => function () use (&$locator) { return $locator->get('baz'); }, - 'baz' => function () use (&$locator) { return $locator->get('bar'); }, - ]); - - $locator->get('foo'); } } diff --git a/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php new file mode 100644 index 00000000..a0f20a6a --- /dev/null +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceLocatorTrait; + +abstract class ServiceLocatorTestCase extends TestCase +{ + protected function getServiceLocator(array $factories): ContainerInterface + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + function () { return 'dummy'; }, + ]); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + public function testThrowsOnUndefinedInternalService() + { + if (!$this->getExpectedException()) { + $this->expectException(\Psr\Container\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 = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } + + public function testThrowsOnCircularReference() + { + $this->expectException(\Psr\Container\ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } +} diff --git a/vendor/symfony/service-contracts/composer.json b/vendor/symfony/service-contracts/composer.json index 36b0d95e..a64188b5 100644 --- a/vendor/symfony/service-contracts/composer.json +++ b/vendor/symfony/service-contracts/composer.json @@ -22,9 +22,6 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" }, "exclude-from-classmap": [ @@ -34,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/vendor/symfony/string/AbstractUnicodeString.php b/vendor/symfony/string/AbstractUnicodeString.php index 2a2bed71..d19a61a9 100644 --- a/vendor/symfony/string/AbstractUnicodeString.php +++ b/vendor/symfony/string/AbstractUnicodeString.php @@ -40,10 +40,6 @@ abstract class AbstractUnicodeString extends AbstractString private const FOLD_FROM = ['İ', 'µ', 'ſ', "\xCD\x85", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "\xE1\xBE\xBE", 'ß', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ']; private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ']; - // the subset of upper case mappings that map one code point to many code points - private const UPPER_FROM = ['ß', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'և', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ', 'ʼn', 'ΐ', 'ΰ', 'ǰ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾶ', 'ῆ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'ῢ', 'ΰ', 'ῤ', 'ῦ', 'ῧ', 'ῶ']; - private const UPPER_TO = ['SS', 'FF', 'FI', 'FL', 'FFI', 'FFL', 'ST', 'ST', 'ԵՒ', 'ՄՆ', 'ՄԵ', 'ՄԻ', 'ՎՆ', 'ՄԽ', 'ʼN', 'Ϊ́', 'Ϋ́', 'J̌', 'H̱', 'T̈', 'W̊', 'Y̊', 'Aʾ', 'Υ̓', 'Υ̓̀', 'Υ̓́', 'Υ̓͂', 'Α͂', 'Η͂', 'Ϊ̀', 'Ϊ́', 'Ι͂', 'Ϊ͂', 'Ϋ̀', 'Ϋ́', 'Ρ̓', 'Υ͂', 'Ϋ͂', 'Ω͂']; - // the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆']; private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; @@ -159,7 +155,9 @@ abstract class AbstractUnicodeString extends AbstractString public function camel(): static { $str = clone $this; - $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) use (&$i) { + $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/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'); }, preg_replace('/[^\pL0-9]++/u', ' ', $this->string))); @@ -360,9 +358,7 @@ abstract class AbstractUnicodeString extends AbstractString $limit = $allWords ? -1 : 1; - $str->string = preg_replace_callback('/\b./u', static function (array $m): string { - return mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); - }, $str->string, $limit); + $str->string = preg_replace_callback('/\b./u', static fn (array $m): string => mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'), $str->string, $limit); return $str; } diff --git a/vendor/symfony/string/Inflector/EnglishInflector.php b/vendor/symfony/string/Inflector/EnglishInflector.php index 4474736a..2871e4e5 100644 --- a/vendor/symfony/string/Inflector/EnglishInflector.php +++ b/vendor/symfony/string/Inflector/EnglishInflector.php @@ -55,6 +55,9 @@ final class EnglishInflector implements InflectorInterface // indices (index), appendices (appendix), prices (price) ['seci', 4, false, true, ['ex', 'ix', 'ice']], + // codes (code) + ['sedoc', 5, false, true, 'code'], + // selfies (selfie) ['seifles', 7, true, true, 'selfie'], @@ -64,6 +67,9 @@ final class EnglishInflector implements InflectorInterface // movies (movie) ['seivom', 6, true, true, 'movie'], + // names (name) + ['seman', 5, true, false, 'name'], + // conspectuses (conspectus), prospectuses (prospectus) ['sesutcep', 8, true, true, 'pectus'], diff --git a/vendor/symfony/string/LazyString.php b/vendor/symfony/string/LazyString.php index 9523b8cd..3128ebb3 100644 --- a/vendor/symfony/string/LazyString.php +++ b/vendor/symfony/string/LazyString.php @@ -30,7 +30,9 @@ class LazyString implements \Stringable, \JsonSerializable } $lazyString = new static(); - $lazyString->value = static function () use (&$callback, &$arguments, &$value): string { + $lazyString->value = static function () use (&$callback, &$arguments): string { + static $value; + if (null !== $arguments) { if (!\is_callable($callback)) { $callback[0] = $callback[0](); diff --git a/vendor/symfony/string/Slugger/AsciiSlugger.php b/vendor/symfony/string/Slugger/AsciiSlugger.php index 826d07ca..6e550c61 100644 --- a/vendor/symfony/string/Slugger/AsciiSlugger.php +++ b/vendor/symfony/string/Slugger/AsciiSlugger.php @@ -74,6 +74,9 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } + /** + * @return void + */ public function setLocale(string $locale) { $this->defaultLocale = $locale; @@ -121,9 +124,7 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface // If the symbols map is passed as a closure, there is no need to fallback to the parent locale // as the closure can just provide substitutions for all locales of interest. $symbolsMap = $this->symbolsMap; - array_unshift($transliterator, static function ($s) use ($symbolsMap, $locale) { - return $symbolsMap($s, $locale); - }); + array_unshift($transliterator, static fn ($s) => $symbolsMap($s, $locale)); } $unicodeString = (new UnicodeString($string))->ascii($transliterator); diff --git a/vendor/symfony/string/composer.json b/vendor/symfony/string/composer.json index 44a809d5..3545c853 100644 --- a/vendor/symfony/string/composer.json +++ b/vendor/symfony/string/composer.json @@ -26,11 +26,11 @@ "symfony/error-handler": "^5.4|^6.0", "symfony/intl": "^6.2", "symfony/http-client": "^5.4|^6.0", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "autoload": { "psr-4": { "Symfony\\Component\\String\\": "" }, diff --git a/www/admin/class_test.hash.php b/www/admin/class_test.hash.php index 0c2d6aeb..0392ae09 100644 --- a/www/admin/class_test.hash.php +++ b/www/admin/class_test.hash.php @@ -43,12 +43,19 @@ print "S::__SHA1SHORT(off): $to_crc: " . $hash_class::__sha1short($to_crc) . ""; print "S::__hash(d): " . $to_crc . "/" . Hash::STANDARD_HASH_SHORT . ": " . $hash_class::__hash($to_crc) . "
"; -foreach (['adler32', 'fnv132', 'fnv1a32', 'joaat'] as $__hash_c) { +foreach (['adler32', 'fnv132', 'fnv1a32', 'joaat', 'sha512'] as $__hash_c) { print "S::__hash($__hash_c): $to_crc: " . $hash_class::__hash($to_crc, $__hash_c) . "
"; } // static use print "U-S::__CRC32B: $to_crc: " . Hash::__crc32b($to_crc) . "
"; +echo "
"; +$text = 'Some String Text'; +$type = 'crc32b'; +print "Hash: " . $type . ": " . hash($type, $text) . "
"; +print "Class: " . $type . ": " . Hash::__hash($text, $type) . "
"; + +echo "
"; print "
CURRENT STANDARD_HASH_SHORT: " . Hash::STANDARD_HASH_SHORT . "
"; print "
CURRENT STANDARD_HASH_LONG: " . Hash::STANDARD_HASH_LONG . "
"; print "HASH SHORT: " . $to_crc . ": " . Hash::__hash($to_crc) . "
"; diff --git a/www/admin/class_test.image.php b/www/admin/class_test.image.php index a773a5f5..cabc8814 100644 --- a/www/admin/class_test.image.php +++ b/www/admin/class_test.image.php @@ -85,7 +85,7 @@ foreach ($images as $image) { $image = BASE . LAYOUT . CONTENT_PATH . IMAGES . $image; list ($height, $width, $img_type) = \CoreLibs\Convert\SetVarType::setArray(getimagesize($image)); echo "
IMAGE INFO: " . $height . "x" . $width . ", TYPE: " - . \CoreLibs\Debug\Support::printArray($img_type) . " [" . $finfo->file($image) . "]
"; + . \CoreLibs\Debug\Support::dumpVar($img_type) . " [" . $finfo->file($image) . "]"; // rotate image first Image::correctImageOrientation($image); // thumbnail tests diff --git a/www/admin/class_test.logging.php b/www/admin/class_test.logging.php index 87f25ac9..7ac13765 100644 --- a/www/admin/class_test.logging.php +++ b/www/admin/class_test.logging.php @@ -1,4 +1,4 @@ -getName() . "
"; print "Flag: per_run getName(): " . Flag::per_class->getName() . "
"; print "Flag: per_run ->name: " . Flag::per_class->name . "
"; print "Flag: per_run ->value: " . Flag::per_class->value . "
"; +$log->setLogUniqueId(); +print "LogUniqId: " . $log->getLogUniqueId() . "
"; print "DUMP: " . $log->dV(['something' => 'error']) . "
"; @@ -82,6 +84,26 @@ try { 'log_file_id' => 'a', ]); */ +// @codingStandardsIgnoreLine +Class TestP +{ + /** @var \CoreLibs\Logging\Logging */ + public $log; + public function __construct( + \CoreLibs\Logging\Logging $log + ) { + $this->log = $log; + } + + public function test(): void + { + $this->log->info('TestL::test call'); + } +} + +$tl = new TestP($log); +$tl->test(); + print '
' . '
' // . '
'
diff --git a/www/admin/class_test.uids.php b/www/admin/class_test.uids.php
index 9aef4bdf..715f6df5 100644
--- a/www/admin/class_test.uids.php
+++ b/www/admin/class_test.uids.php
@@ -39,11 +39,16 @@ print "UUIDV4: " . $_uids->uuidv4() . "
"; print "UNIQID (d): " . $_uids->uniqId() . "
"; print "UNIQID (md5): " . $_uids->uniqId('md5') . "
"; print "UNIQID (sha256): " . $_uids->uniqId('sha256') . "
"; -// statc +// static print "S::UUIDV4: " . $uids_class::uuidv4() . "
"; print "S::UNIQID (d): " . $uids_class::uniqId() . "
"; print "S::UNIQID (md5): " . $uids_class::uniqId('md5') . "
"; print "S::UNIQID (sha256): " . $uids_class::uniqId('sha256') . "
"; +// with direct length +print "S:UNIQID (0->4): " . Uids::uniqId(0) . "
"; +print "S:UNIQID (9->8): " . Uids::uniqId(9) . "
"; +print "S:UNIQID (9,true): " . Uids::uniqId(9, true) . "
"; +print "S:UNIQID (512): " . Uids::uniqId(512) . "
"; // uniq ids print "UNIQU ID SHORT : " . Uids::uniqIdShort() . "
"; print "UNIQU ID LONG : " . Uids::uniqIdLong() . "
";