diff --git a/app/composer.json b/app/composer.json index 1726aa9c5..0cf05a49e 100644 --- a/app/composer.json +++ b/app/composer.json @@ -6,7 +6,7 @@ "license": "MIT", "require": { "php": ">=7.3", - "cakephp/cakephp": "^4.4", + "cakephp/cakephp": "^4.6", "cakephp/migrations": "^3.2", "cakephp/plugin-installer": "^1.3", "components/jquery": "~3.7", diff --git a/app/composer.lock b/app/composer.lock index c9c36f6ad..83c4e3f8b 100644 --- a/app/composer.lock +++ b/app/composer.lock @@ -4,24 +4,24 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0d865a4843fd23d964c2c327103cde7a", + "content-hash": "045a03af4d52855cfb0f3dc247c30ca1", "packages": [ { "name": "cakephp/cakephp", - "version": "4.4.17", + "version": "4.6.1", "source": { "type": "git", "url": "https://github.com/cakephp/cakephp.git", - "reference": "9ff254d6d60720089dec1e10aa1907e24e39a98e" + "reference": "d3c196c92fde430dc395b14b058dd240c3de42be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/cakephp/zipball/9ff254d6d60720089dec1e10aa1907e24e39a98e", - "reference": "9ff254d6d60720089dec1e10aa1907e24e39a98e", + "url": "https://api.github.com/repos/cakephp/cakephp/zipball/d3c196c92fde430dc395b14b058dd240c3de42be", + "reference": "d3c196c92fde430dc395b14b058dd240c3de42be", "shasum": "" }, "require": { - "cakephp/chronos": "^2.2", + "cakephp/chronos": "^2.4.0-RC2", "composer/ca-bundle": "^1.2", "ext-intl": "*", "ext-json": "*", @@ -29,7 +29,7 @@ "laminas/laminas-diactoros": "^2.2.2", "laminas/laminas-httphandlerrunner": "^1.1 || ^2.0", "league/container": "^4.2.0", - "php": ">=7.4.0", + "php": ">=7.4.0,<9", "psr/container": "^1.1 || ^2.0", "psr/http-client": "^1.0", "psr/http-server-handler": "^1.0", @@ -65,7 +65,7 @@ "require-dev": { "cakephp/cakephp-codesniffer": "^4.5", "mikey179/vfsstream": "^1.6.10", - "paragonie/csp-builder": "^2.3", + "paragonie/csp-builder": "^2.3 || ^3.0", "phpunit/phpunit": "^8.5 || ^9.3" }, "suggest": { @@ -78,6 +78,7 @@ "autoload": { "files": [ "src/Core/functions.php", + "src/Error/functions.php", "src/Collection/functions.php", "src/I18n/functions.php", "src/Routing/functions.php", @@ -116,20 +117,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/cakephp" }, - "time": "2023-08-20T02:36:22+00:00" + "time": "2025-04-26T22:40:45+00:00" }, { "name": "cakephp/chronos", - "version": "2.4.1", + "version": "2.4.5", "source": { "type": "git", "url": "https://github.com/cakephp/chronos.git", - "reference": "dd583900b26971e84d56c482d6c5fc16961bd103" + "reference": "b0321ab7658af9e7abcb3dd876f226e6f3dbb81f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/chronos/zipball/dd583900b26971e84d56c482d6c5fc16961bd103", - "reference": "dd583900b26971e84d56c482d6c5fc16961bd103", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/b0321ab7658af9e7abcb3dd876f226e6f3dbb81f", + "reference": "b0321ab7658af9e7abcb3dd876f226e6f3dbb81f", "shasum": "" }, "require": { @@ -174,7 +175,7 @@ "issues": "https://github.com/cakephp/chronos/issues", "source": "https://github.com/cakephp/chronos" }, - "time": "2023-09-12T03:12:29+00:00" + "time": "2024-07-30T22:26:11+00:00" }, { "name": "cakephp/migrations", @@ -287,30 +288,30 @@ }, { "name": "components/jquery", - "version": "3.6.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/components/jquery.git", - "reference": "6cf38ee1fd04b6adf8e7dda161283aa35be818c3" + "reference": "8edc7785239bb8c2ad2b83302b856a1d61de60e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/components/jquery/zipball/6cf38ee1fd04b6adf8e7dda161283aa35be818c3", - "reference": "6cf38ee1fd04b6adf8e7dda161283aa35be818c3", + "url": "https://api.github.com/repos/components/jquery/zipball/8edc7785239bb8c2ad2b83302b856a1d61de60e7", + "reference": "8edc7785239bb8c2ad2b83302b856a1d61de60e7", "shasum": "" }, "type": "component", "extra": { "component": { - "scripts": [ - "jquery.js" - ], "files": [ "jquery.min.js", "jquery.min.map", "jquery.slim.js", "jquery.slim.min.js", "jquery.slim.min.map" + ], + "scripts": [ + "jquery.js" ] } }, @@ -332,32 +333,32 @@ "source": "https://github.com/jquery/jquery", "wiki": "http://docs.jquery.com/" }, - "time": "2021-03-20T19:13:42+00:00" + "time": "2023-09-22T01:43:46+00:00" }, { "name": "composer/ca-bundle", - "version": "1.3.7", + "version": "1.5.6", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "76e46335014860eec1aa5a724799a00a2e47cc85" + "reference": "f65c239c970e7f072f067ab78646e9f0b2935175" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/76e46335014860eec1aa5a724799a00a2e47cc85", - "reference": "76e46335014860eec1aa5a724799a00a2e47cc85", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/f65c239c970e7f072f067ab78646e9f0b2935175", + "reference": "f65c239c970e7f072f067ab78646e9f0b2935175", "shasum": "" }, "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", "extra": { @@ -392,7 +393,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.3.7" + "source": "https://github.com/composer/ca-bundle/tree/1.5.6" }, "funding": [ { @@ -408,7 +409,7 @@ "type": "tidelift" } ], - "time": "2023-08-30T09:31:38+00:00" + "time": "2025-03-06T14:30:56+00:00" }, { "name": "doctrine/cache", @@ -505,16 +506,16 @@ }, { "name": "doctrine/dbal", - "version": "3.7.0", + "version": "3.9.4", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf" + "reference": "ec16c82f20be1a7224e65ac67144a29199f87959" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/00d03067f07482f025d41ab55e4ba0db5eca2cdf", - "reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/ec16c82f20be1a7224e65ac67144a29199f87959", + "reference": "ec16c82f20be1a7224e65ac67144a29199f87959", "shasum": "" }, "require": { @@ -530,15 +531,13 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.35", - "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "9.6.13", - "psalm/plugin-phpunit": "0.18.4", + "phpstan/phpstan": "2.1.1", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "9.6.22", "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.7.2", - "symfony/cache": "^5.4|^6.0", - "symfony/console": "^4.4|^5.4|^6.0", - "vimeo/psalm": "4.30.0" + "squizlabs/php_codesniffer": "3.10.2", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/console": "^4.4|^5.4|^6.0|^7.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -598,7 +597,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.7.0" + "source": "https://github.com/doctrine/dbal/tree/3.9.4" }, "funding": [ { @@ -614,33 +613,34 @@ "type": "tidelift" } ], - "time": "2023-09-26T20:56:55+00:00" + "time": "2025-01-16T08:28:55+00:00" }, { "name": "doctrine/deprecations", - "version": "v1.1.1", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "psr/log": "^1 || ^2 || ^3" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -648,7 +648,7 @@ "type": "library", "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + "Doctrine\\Deprecations\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -659,22 +659,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" }, - "time": "2023-06-03T09:27:29+00:00" + "time": "2025-04-07T20:06:18+00:00" }, { "name": "doctrine/event-manager", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32" + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", "shasum": "" }, "require": { @@ -684,10 +684,10 @@ "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^10", + "doctrine/coding-standard": "^12", "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.28" + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^5.24" }, "type": "library", "autoload": { @@ -736,7 +736,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.0.0" + "source": "https://github.com/doctrine/event-manager/tree/2.0.1" }, "funding": [ { @@ -752,24 +752,24 @@ "type": "tidelift" } ], - "time": "2022-10-12T20:59:15+00:00" + "time": "2024-05-22T20:47:39+00:00" }, { "name": "laminas/laminas-diactoros", - "version": "2.25.2", + "version": "2.26.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-diactoros.git", - "reference": "9f3f4bf5b99c9538b6f1dbcc20f6fec357914f9e" + "reference": "6584d44eb8e477e89d453313b858daac6183cddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/9f3f4bf5b99c9538b6f1dbcc20f6fec357914f9e", - "reference": "9f3f4bf5b99c9538b6f1dbcc20f6fec357914f9e", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/6584d44eb8e477e89d453313b858daac6183cddc", + "reference": "6584d44eb8e477e89d453313b858daac6183cddc", "shasum": "" }, "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "psr/http-factory": "^1.0", "psr/http-message": "^1.1" }, @@ -795,8 +795,8 @@ "type": "library", "extra": { "laminas": { - "config-provider": "Laminas\\Diactoros\\ConfigProvider", - "module": "Laminas\\Diactoros" + "module": "Laminas\\Diactoros", + "config-provider": "Laminas\\Diactoros\\ConfigProvider" } }, "autoload": { @@ -849,34 +849,34 @@ "type": "community_bridge" } ], - "time": "2023-04-17T15:44:17+00:00" + "time": "2023-10-29T16:17:44+00:00" }, { "name": "laminas/laminas-httphandlerrunner", - "version": "2.9.0", + "version": "2.11.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-httphandlerrunner.git", - "reference": "d3e84755a17e563b1c5f8290cbfb150210501a77" + "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/d3e84755a17e563b1c5f8290cbfb150210501a77", - "reference": "d3e84755a17e563b1c5f8290cbfb150210501a77", + "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/c428d9f67f280d155637cbe2b7245b5188c8cdae", + "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "psr/http-message": "^1.0 || ^2.0", "psr/http-message-implementation": "^1.0 || ^2.0", "psr/http-server-handler": "^1.0" }, "require-dev": { - "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-diactoros": "^3.0.0", - "phpunit/phpunit": "^10.1.2", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.11" + "laminas/laminas-coding-standard": "~3.0.0", + "laminas/laminas-diactoros": "^3.4.0", + "phpunit/phpunit": "^10.5.36", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" }, "type": "library", "extra": { @@ -916,20 +916,20 @@ "type": "community_bridge" } ], - "time": "2023-09-04T10:43:03+00:00" + "time": "2024-10-17T20:37:17+00:00" }, { "name": "league/container", - "version": "4.2.0", + "version": "4.2.4", "source": { "type": "git", "url": "https://github.com/thephpleague/container.git", - "reference": "375d13cb828649599ef5d48a339c4af7a26cd0ab" + "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/375d13cb828649599ef5d48a339c4af7a26cd0ab", - "reference": "375d13cb828649599ef5d48a339c4af7a26cd0ab", + "url": "https://api.github.com/repos/thephpleague/container/zipball/7ea728b013b9a156c409c6f0fc3624071b742dec", + "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec", "shasum": "" }, "require": { @@ -954,11 +954,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev", - "dev-4.x": "4.x-dev", - "dev-3.x": "3.x-dev", + "dev-1.x": "1.x-dev", "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "4.x-dev" } }, "autoload": { @@ -990,7 +990,7 @@ ], "support": { "issues": "https://github.com/thephpleague/container/issues", - "source": "https://github.com/thephpleague/container/tree/4.2.0" + "source": "https://github.com/thephpleague/container/tree/4.2.4" }, "funding": [ { @@ -998,27 +998,27 @@ "type": "github" } ], - "time": "2021-11-16T10:29:06+00:00" + "time": "2024-11-10T12:42:13+00:00" }, { "name": "mobiledetect/mobiledetectlib", - "version": "2.8.41", + "version": "2.8.45", "source": { "type": "git", "url": "https://github.com/serbanghita/Mobile-Detect.git", - "reference": "fc9cccd4d3706d5a7537b562b59cc18f9e4c0cb1" + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/fc9cccd4d3706d5a7537b562b59cc18f9e4c0cb1", - "reference": "fc9cccd4d3706d5a7537b562b59cc18f9e4c0cb1", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/96aaebcf4f50d3d2692ab81d2c5132e425bca266", + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266", "shasum": "" }, "require": { "php": ">=5.0.0" }, "require-dev": { - "phpunit/phpunit": "~4.8.35||~5.7" + "phpunit/phpunit": "~4.8.36" }, "type": "library", "autoload": { @@ -1052,9 +1052,15 @@ ], "support": { "issues": "https://github.com/serbanghita/Mobile-Detect/issues", - "source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.41" + "source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.45" }, - "time": "2022-11-08T18:31:26+00:00" + "funding": [ + { + "url": "https://github.com/serbanghita", + "type": "github" + } + ], + "time": "2023-11-07T21:57:25+00:00" }, { "name": "psr/cache", @@ -1212,20 +1218,20 @@ }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -1249,7 +1255,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -1261,9 +1267,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -1620,22 +1626,22 @@ }, { "name": "symfony/config", - "version": "v6.3.2", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467" + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", - "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", + "url": "https://api.github.com/repos/symfony/config/zipball/4e55e7e4ffddd343671ea972216d4509f46c22ef", + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -1643,11 +1649,11 @@ "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0" + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1675,7 +1681,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.3.2" + "source": "https://github.com/symfony/config/tree/v6.4.14" }, "funding": [ { @@ -1691,20 +1697,20 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:22:16+00:00" + "time": "2024-11-04T11:33:53+00:00" }, { "name": "symfony/console", - "version": "v6.3.4", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6" + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6", - "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6", + "url": "https://api.github.com/repos/symfony/console/zipball/a3011c7b7adb58d89f6c0d822abb641d7a5f9719", + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719", "shasum": "" }, "require": { @@ -1712,7 +1718,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0" + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/dependency-injection": "<5.4", @@ -1726,12 +1732,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/lock": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -1765,7 +1775,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.3.4" + "source": "https://github.com/symfony/console/tree/v6.4.21" }, "funding": [ { @@ -1781,20 +1791,20 @@ "type": "tidelift" } ], - "time": "2023-08-16T10:10:12+00:00" + "time": "2025-04-07T15:42:41+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.3.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -1802,12 +1812,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -1832,7 +1842,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.3.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -1848,27 +1858,30 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/filesystem", - "version": "v6.3.1", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, "type": "library", "autoload": { "psr-4": { @@ -1895,7 +1908,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.3.1" + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" }, "funding": [ { @@ -1911,24 +1924,24 @@ "type": "tidelift" } ], - "time": "2023-06-01T08:30:39+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -1938,12 +1951,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1977,7 +1987,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -1993,36 +2003,33 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.28.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "875e90aeea2777b6f135677f618529449334a612" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", - "reference": "875e90aeea2777b6f135677f618529449334a612", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2058,7 +2065,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -2074,36 +2081,33 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.28.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2142,7 +2146,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -2158,24 +2162,25 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -2185,12 +2190,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2225,7 +2227,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -2241,37 +2243,38 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.3.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", - "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -2307,7 +2310,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -2323,24 +2326,24 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/string", - "version": "v6.3.2", + "version": "v7.2.6", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "53d1a83225002635bca3482fcbf963001313fb68" + "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", - "reference": "53d1a83225002635bca3482fcbf963001313fb68", + "url": "https://api.github.com/repos/symfony/string/zipball/a214fe7d62bd4df2a76447c67c6b26e1d5e74931", + "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -2350,11 +2353,12 @@ "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/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/var-exporter": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -2393,7 +2397,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.3.2" + "source": "https://github.com/symfony/string/tree/v7.2.6" }, "funding": [ { @@ -2409,20 +2413,20 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2025-04-20T20:18:16+00:00" }, { "name": "twbs/bootstrap", - "version": "v5.3.2", + "version": "v5.3.6", "source": { "type": "git", "url": "https://github.com/twbs/bootstrap.git", - "reference": "344e912d04b5b6a04482113eff20ab416ff01048" + "reference": "f849680d16a9695c9a6c9c062d6cff55ddcf071e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twbs/bootstrap/zipball/344e912d04b5b6a04482113eff20ab416ff01048", - "reference": "344e912d04b5b6a04482113eff20ab416ff01048", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/f849680d16a9695c9a6c9c062d6cff55ddcf071e", + "reference": "f849680d16a9695c9a6c9c062d6cff55ddcf071e", "shasum": "" }, "replace": { @@ -2457,9 +2461,9 @@ ], "support": { "issues": "https://github.com/twbs/bootstrap/issues", - "source": "https://github.com/twbs/bootstrap/tree/v5.3.2" + "source": "https://github.com/twbs/bootstrap/tree/v5.3.6" }, - "time": "2023-09-14T14:19:27+00:00" + "time": "2025-05-05T19:21:55+00:00" } ], "packages-dev": [ @@ -2623,23 +2627,23 @@ }, { "name": "cakephp/debug_kit", - "version": "4.9.4", + "version": "4.10.2", "source": { "type": "git", "url": "https://github.com/cakephp/debug_kit.git", - "reference": "663491edec4a6b9111f1cf4733ebd471450df71e" + "reference": "49c841e4b2b89e4d1cb7c3ce00d27e3d5f2bdbd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/663491edec4a6b9111f1cf4733ebd471450df71e", - "reference": "663491edec4a6b9111f1cf4733ebd471450df71e", + "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/49c841e4b2b89e4d1cb7c3ce00d27e3d5f2bdbd4", + "reference": "49c841e4b2b89e4d1cb7c3ce00d27e3d5f2bdbd4", "shasum": "" }, "require": { - "cakephp/cakephp": "^4.4.0", + "cakephp/cakephp": "^4.5.0", "cakephp/chronos": "^2.0", "composer/composer": "^1.3 | ^2.0", - "jdorn/sql-formatter": "^1.2", + "doctrine/sql-formatter": "^1.1.3", "php": ">=7.4" }, "require-dev": { @@ -2677,6 +2681,7 @@ "keywords": [ "cakephp", "debug", + "dev", "kit" ], "support": { @@ -2685,7 +2690,7 @@ "issues": "https://github.com/cakephp/debug_kit/issues", "source": "https://github.com/cakephp/debug_kit" }, - "time": "2023-07-05T16:04:04+00:00" + "time": "2023-12-15T20:59:05+00:00" }, { "name": "cakephp/repl", @@ -2746,24 +2751,23 @@ }, { "name": "cakephp/twig-view", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/cakephp/twig-view.git", - "reference": "14df50360b809a171d0688020fbdfe513763f89b" + "reference": "e4a18e91e004730ccbaf796bde60612e8afac0e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/twig-view/zipball/14df50360b809a171d0688020fbdfe513763f89b", - "reference": "14df50360b809a171d0688020fbdfe513763f89b", + "url": "https://api.github.com/repos/cakephp/twig-view/zipball/e4a18e91e004730ccbaf796bde60612e8afac0e8", + "reference": "e4a18e91e004730ccbaf796bde60612e8afac0e8", "shasum": "" }, "require": { "cakephp/cakephp": "^4.0", "jasny/twig-extensions": "^1.3", - "php": ">=7.2", "twig/markdown-extra": "^3.0", - "twig/twig": "^3.0" + "twig/twig": "^3.11.0" }, "conflict": { "wyrihaximus/twig-view": "*" @@ -2805,20 +2809,20 @@ "issues": "https://github.com/cakephp/twig-view/issues", "source": "https://github.com/cakephp/twig-view" }, - "time": "2021-09-17T14:07:52+00:00" + "time": "2024-10-11T06:25:59+00:00" }, { "name": "composer/class-map-generator", - "version": "1.1.0", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9" + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/953cc4ea32e0c31f2185549c7d216d7921f03da9", - "reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/134b705ddb0025d397d8318a75825fe3c9d1da34", + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34", "shasum": "" }, "require": { @@ -2827,12 +2831,12 @@ "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" }, "require-dev": { - "phpstan/phpstan": "^1.6", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/filesystem": "^5.4 || ^6", - "symfony/phpunit-bridge": "^5" + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" }, "type": "library", "extra": { @@ -2862,7 +2866,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.1.0" + "source": "https://github.com/composer/class-map-generator/tree/1.6.1" }, "funding": [ { @@ -2878,28 +2882,28 @@ "type": "tidelift" } ], - "time": "2023-06-30T13:58:57+00:00" + "time": "2025-03-24T13:50:44+00:00" }, { "name": "composer/composer", - "version": "2.6.3", + "version": "2.7.7", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "ff477832e6d838a736556d4a39a3b80f4412abfd" + "reference": "291942978f39435cf904d33739f98d7d4eca7b23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/ff477832e6d838a736556d4a39a3b80f4412abfd", - "reference": "ff477832e6d838a736556d4a39a3b80f4412abfd", + "url": "https://api.github.com/repos/composer/composer/zipball/291942978f39435cf904d33739f98d7d4eca7b23", + "reference": "291942978f39435cf904d33739f98d7d4eca7b23", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0", - "composer/class-map-generator": "^1.0", + "composer/class-map-generator": "^1.3.3", "composer/metadata-minifier": "^1.0", "composer/pcre": "^2.1 || ^3.1", - "composer/semver": "^3.2.5", + "composer/semver": "^3.3", "composer/spdx-licenses": "^1.5.7", "composer/xdebug-handler": "^2.0.2 || ^3.0.3", "justinrainbow/json-schema": "^5.2.11", @@ -2918,12 +2922,12 @@ "symfony/process": "^5.4 || ^6.0 || ^7" }, "require-dev": { - "phpstan/phpstan": "^1.9.3", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1", - "phpstan/phpstan-symfony": "^1.2.10", - "symfony/phpunit-bridge": "^6.0 || ^7" + "phpstan/phpstan": "^1.11.0", + "phpstan/phpstan-deprecation-rules": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpstan/phpstan-strict-rules": "^1.6.0", + "phpstan/phpstan-symfony": "^1.4.0", + "symfony/phpunit-bridge": "^6.4.1 || ^7.0.1" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -2935,13 +2939,13 @@ ], "type": "library", "extra": { - "branch-alias": { - "dev-main": "2.6-dev" - }, "phpstan": { "includes": [ "phpstan/rules.neon" ] + }, + "branch-alias": { + "dev-main": "2.7-dev" } }, "autoload": { @@ -2976,7 +2980,7 @@ "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.6.3" + "source": "https://github.com/composer/composer/tree/2.7.7" }, "funding": [ { @@ -2992,7 +2996,7 @@ "type": "tidelift" } ], - "time": "2023-09-15T07:38:22+00:00" + "time": "2024-06-10T20:11:12+00:00" }, { "name": "composer/metadata-minifier", @@ -3065,16 +3069,16 @@ }, { "name": "composer/pcre", - "version": "3.1.0", + "version": "3.1.4", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" + "reference": "04229f163664973f68f38f6f73d917799168ef24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "url": "https://api.github.com/repos/composer/pcre/zipball/04229f163664973f68f38f6f73d917799168ef24", + "reference": "04229f163664973f68f38f6f73d917799168ef24", "shasum": "" }, "require": { @@ -3116,7 +3120,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.0" + "source": "https://github.com/composer/pcre/tree/3.1.4" }, "funding": [ { @@ -3132,28 +3136,28 @@ "type": "tidelift" } ], - "time": "2022-11-17T09:50:14+00:00" + "time": "2024-05-27T13:40:54+00:00" }, { "name": "composer/semver", - "version": "3.4.0", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -3197,7 +3201,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -3213,20 +3217,20 @@ "type": "tidelift" } ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.5.7", + "version": "1.5.8", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "c848241796da2abf65837d51dce1fae55a960149" + "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/c848241796da2abf65837d51dce1fae55a960149", - "reference": "c848241796da2abf65837d51dce1fae55a960149", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", + "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", "shasum": "" }, "require": { @@ -3275,9 +3279,9 @@ "validator" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.7" + "source": "https://github.com/composer/spdx-licenses/tree/1.5.8" }, "funding": [ { @@ -3293,20 +3297,20 @@ "type": "tidelift" } ], - "time": "2022-05-23T07:37:50+00:00" + "time": "2023-11-20T07:44:33+00:00" }, { "name": "composer/xdebug-handler", - "version": "3.0.3", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -3317,7 +3321,7 @@ "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "type": "library", "autoload": { @@ -3341,9 +3345,9 @@ "performance" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -3359,7 +3363,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T21:32:43+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", @@ -3510,37 +3514,35 @@ "time": "2022-12-30T00:23:10+00:00" }, { - "name": "jasny/twig-extensions", - "version": "v1.3.0", + "name": "doctrine/sql-formatter", + "version": "1.5.2", "source": { "type": "git", - "url": "https://github.com/jasny/twig-extensions.git", - "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b" + "url": "https://github.com/doctrine/sql-formatter.git", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/a694eb02f6fc14ff8e2fceb8b80882c0c926102b", - "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8", "shasum": "" }, "require": { - "php": ">=7.0.0", - "twig/twig": "^2.0 | ^3.0" + "php": "^8.1" }, "require-dev": { - "ext-intl": "*", - "ext-pcre": "*", - "jasny/php-code-quality": "^2.5", - "php": ">=7.2.0" - }, - "suggest": { - "ext-intl": "Required for the use of the LocalDate Twig extension", - "ext-pcre": "Required for the use of the PCRE Twig extension" + "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5" }, + "bin": [ + "bin/sql-formatter" + ], "type": "library", "autoload": { "psr-4": { - "Jasny\\Twig\\": "src/" + "Doctrine\\SqlFormatter\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -3549,60 +3551,58 @@ ], "authors": [ { - "name": "Arnold Daniels", - "email": "arnold@jasny.net", - "homepage": "http://www.jasny.net" + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "https://jeremydorn.com/" } ], - "description": "A set of useful Twig filters", - "homepage": "http://github.com/jasny/twig-extensions#README", + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/doctrine/sql-formatter/", "keywords": [ - "PCRE", - "array", - "date", - "datetime", - "preg", - "regex", - "templating", - "text", - "time" + "highlight", + "sql" ], "support": { - "issues": "https://github.com/jasny/twig-extensions/issues", - "source": "https://github.com/jasny/twig-extensions" + "issues": "https://github.com/doctrine/sql-formatter/issues", + "source": "https://github.com/doctrine/sql-formatter/tree/1.5.2" }, - "time": "2019-12-10T16:04:23+00:00" + "time": "2025-01-24T11:45:48+00:00" }, { - "name": "jdorn/sql-formatter", - "version": "v1.2.17", + "name": "jasny/twig-extensions", + "version": "v1.3.1", "source": { "type": "git", - "url": "https://github.com/jdorn/sql-formatter.git", - "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc" + "url": "https://github.com/jasny/twig-extensions.git", + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc", - "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc", + "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/8a5ca5f49317bf421a519556ad2e876820d41e01", + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01", "shasum": "" }, "require": { - "php": ">=5.2.4" + "php": ">=7.4.0", + "twig/twig": "^2.7 | ^3.0" }, "require-dev": { - "phpunit/phpunit": "3.7.*" + "ext-intl": "*", + "ext-json": "*", + "ext-pcre": "*", + "phpstan/phpstan": "^1.12.0", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.10" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } + "suggest": { + "ext-intl": "Required for the use of the LocalDate Twig extension", + "ext-pcre": "Required for the use of the PCRE Twig extension" }, + "type": "library", "autoload": { - "classmap": [ - "lib" - ] + "psr-4": { + "Jasny\\Twig\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3610,22 +3610,29 @@ ], "authors": [ { - "name": "Jeremy Dorn", - "email": "jeremy@jeremydorn.com", - "homepage": "http://jeremydorn.com/" + "name": "Arnold Daniels", + "email": "arnold@jasny.net", + "homepage": "http://www.jasny.net" } ], - "description": "a PHP SQL highlighting library", - "homepage": "https://github.com/jdorn/sql-formatter/", + "description": "A set of useful Twig filters", + "homepage": "http://github.com/jasny/twig-extensions#README", "keywords": [ - "highlight", - "sql" + "PCRE", + "array", + "date", + "datetime", + "preg", + "regex", + "templating", + "text", + "time" ], "support": { - "issues": "https://github.com/jdorn/sql-formatter/issues", - "source": "https://github.com/jdorn/sql-formatter/tree/v1.2.17" + "issues": "https://github.com/jasny/twig-extensions/issues", + "source": "https://github.com/jasny/twig-extensions" }, - "time": "2014-01-12T16:20:24+00:00" + "time": "2024-09-03T09:04:53+00:00" }, { "name": "josegonzalez/dotenv", @@ -3686,20 +3693,20 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.12", + "version": "5.3.0", "source": { "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60" + "url": "https://github.com/jsonrainbow/json-schema.git", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", @@ -3710,11 +3717,6 @@ "bin/validate-json" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, "autoload": { "psr-4": { "JsonSchema\\": "src/JsonSchema/" @@ -3749,10 +3751,10 @@ "schema" ], "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" }, - "time": "2022-04-13T08:02:27+00:00" + "time": "2024-07-06T21:00:26+00:00" }, { "name": "m1/env", @@ -3818,16 +3820,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", "shasum": "" }, "require": { @@ -3835,11 +3837,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -3865,7 +3868,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" }, "funding": [ { @@ -3873,29 +3876,29 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2025-04-29T12:36:36+00:00" }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.19.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.1" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -3927,26 +3930,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2024-09-29T15:01:53+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -3987,9 +3991,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -4044,30 +4054,30 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.2", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "bcad8d995980440892759db0c32acae7c8e79442" + "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442", - "reference": "bcad8d995980440892759db0c32acae7c8e79442", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", + "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^5.3.0", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", "symfony/process": "^5.2" }, "type": "library", @@ -4085,9 +4095,9 @@ "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.24.2" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0" }, - "time": "2023-09-26T12:28:12+00:00" + "time": "2025-02-19T13:28:12+00:00" }, { "name": "phpstan/phpstan", @@ -4151,35 +4161,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -4188,7 +4198,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -4217,7 +4227,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -4225,7 +4235,7 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4470,45 +4480,45 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.13", + "version": "9.6.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { @@ -4553,7 +4563,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23" }, "funding": [ { @@ -4564,34 +4574,42 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2023-09-19T05:39:22+00:00" + "time": "2025-05-02T06:40:34+00:00" }, { "name": "psy/psysh", - "version": "v0.11.21", + "version": "v0.12.8", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "bcb22101107f3bf770523b65630c9d547f60c540" + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/bcb22101107f3bf770523b65630c9d547f60c540", - "reference": "bcb22101107f3bf770523b65630c9d547f60c540", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625", "shasum": "" }, "require": { "ext-json": "*", "ext-tokenizer": "*", - "nikic/php-parser": "^4.0 || ^3.1", - "php": "^8.0 || ^7.0.8", - "symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.4", - "symfony/var-dumper": "^6.0 || ^5.0 || ^4.0 || ^3.4" + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" }, "conflict": { "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" @@ -4602,20 +4620,19 @@ "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", "ext-pdo-sqlite": "The doc command requires SQLite to work.", - "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", - "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." }, "bin": [ "bin/psysh" ], "type": "library", "extra": { - "branch-alias": { - "dev-main": "0.11.x-dev" - }, "bamarni-bin": { "bin-links": false, "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" } }, "autoload": { @@ -4647,30 +4664,30 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.21" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.8" }, - "time": "2023-09-17T21:15:54+00:00" + "time": "2025-03-16T03:05:19+00:00" }, { "name": "react/promise", - "version": "v3.0.0", + "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "c86753c76fd3be465d93b308f18d189f01a22be4" + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/c86753c76fd3be465d93b308f18d189f01a22be4", - "reference": "c86753c76fd3be465d93b308f18d189f01a22be4", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", "shasum": "" }, "require": { "php": ">=7.1.0" }, "require-dev": { - "phpstan/phpstan": "1.10.20 || 1.4.10", - "phpunit/phpunit": "^9.5 || ^7.5" + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" }, "type": "library", "autoload": { @@ -4714,7 +4731,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.0.0" + "source": "https://github.com/reactphp/promise/tree/v3.2.0" }, "funding": [ { @@ -4722,20 +4739,20 @@ "type": "open_collective" } ], - "time": "2023-07-11T16:12:49+00:00" + "time": "2024-05-24T10:39:05+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -4770,7 +4787,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -4778,7 +4795,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -4967,20 +4984,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -5012,7 +5029,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -5020,20 +5037,20 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -5078,7 +5095,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -5086,7 +5103,7 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -5153,16 +5170,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -5218,7 +5235,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -5226,20 +5243,20 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -5282,7 +5299,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -5290,24 +5307,24 @@ "type": "github" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -5339,7 +5356,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -5347,7 +5364,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -5526,16 +5543,16 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -5547,7 +5564,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -5568,8 +5585,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -5577,7 +5593,7 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", @@ -5690,23 +5706,23 @@ }, { "name": "seld/jsonlint", - "version": "1.10.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1" + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/594fd6462aad8ecee0b45ca5045acea4776667f1", - "reference": "594fd6462aad8ecee0b45ca5045acea4776667f1", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", "shasum": "" }, "require": { "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.5", + "phpstan/phpstan": "^1.11", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" }, "bin": [ @@ -5726,7 +5742,7 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "JSON Linter", @@ -5738,7 +5754,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.0" + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" }, "funding": [ { @@ -5750,7 +5766,7 @@ "type": "tidelift" } ], - "time": "2023-05-11T13:16:46+00:00" + "time": "2024-07-11T14:55:45+00:00" }, { "name": "seld/phar-utils", @@ -5863,32 +5879,32 @@ }, { "name": "slevomat/coding-standard", - "version": "8.13.4", + "version": "8.18.0", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "4b2af2fb17773656d02fbfb5d18024ebd19fe322" + "reference": "f3b23cb9b26301b8c3c7bb03035a1bee23974593" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/4b2af2fb17773656d02fbfb5d18024ebd19fe322", - "reference": "4b2af2fb17773656d02fbfb5d18024ebd19fe322", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/f3b23cb9b26301b8c3c7bb03035a1bee23974593", + "reference": "f3b23cb9b26301b8c3c7bb03035a1bee23974593", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", - "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": "^1.23.0", - "squizlabs/php_codesniffer": "^3.7.1" + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^2.1.0", + "squizlabs/php_codesniffer": "^3.12.2" }, "require-dev": { - "phing/phing": "2.17.4", - "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.10.26", - "phpstan/phpstan-deprecation-rules": "1.1.3", - "phpstan/phpstan-phpunit": "1.3.13", - "phpstan/phpstan-strict-rules": "1.5.1", - "phpunit/phpunit": "7.5.20|8.5.21|9.6.8|10.2.6" + "phing/phing": "3.0.1", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/phpstan": "2.1.13", + "phpstan/phpstan-deprecation-rules": "2.0.2", + "phpstan/phpstan-phpunit": "2.0.6", + "phpstan/phpstan-strict-rules": "2.0.4", + "phpunit/phpunit": "9.6.8|10.5.45|11.4.4|11.5.17|12.1.3" }, "type": "phpcodesniffer-standard", "extra": { @@ -5912,7 +5928,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.13.4" + "source": "https://github.com/slevomat/coding-standard/tree/8.18.0" }, "funding": [ { @@ -5924,20 +5940,20 @@ "type": "tidelift" } ], - "time": "2023-07-25T10:28:55+00:00" + "time": "2025-05-01T09:40:50+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.2", + "version": "3.12.2", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "6d4cf6032d4b718f168c90a96e36c7d0eaacb2aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/6d4cf6032d4b718f168c90a96e36c7d0eaacb2aa", + "reference": "6d4cf6032d4b718f168c90a96e36c7d0eaacb2aa", "shasum": "" }, "require": { @@ -5947,11 +5963,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -5966,42 +5982,69 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", "standards", "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2023-02-22T23:07:41+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-04-13T04:10:18+00:00" }, { "name": "symfony/finder", - "version": "v6.3.3", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e" + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.0" + "symfony/filesystem": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -6029,7 +6072,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.3.3" + "source": "https://github.com/symfony/finder/tree/v7.2.2" }, "funding": [ { @@ -6045,33 +6088,30 @@ "type": "tidelift" } ], - "time": "2023-07-31T08:31:44+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.28.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -6108,7 +6148,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.32.0" }, "funding": [ { @@ -6124,33 +6164,30 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -6191,7 +6228,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" }, "funding": [ { @@ -6207,33 +6244,30 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.28.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -6270,7 +6304,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" }, "funding": [ { @@ -6286,24 +6320,24 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/process", - "version": "v6.3.4", + "version": "v7.2.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54" + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54", - "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54", + "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "autoload": { @@ -6331,7 +6365,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.3.4" + "source": "https://github.com/symfony/process/tree/v7.2.5" }, "funding": [ { @@ -6347,37 +6381,36 @@ "type": "tidelift" } ], - "time": "2023-08-07T10:39:22+00:00" + "time": "2025-03-13T12:21:46+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.3.4", + "version": "v7.2.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "2027be14f8ae8eae999ceadebcda5b4909b81d45" + "reference": "9c46038cd4ed68952166cf7001b54eb539184ccb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2027be14f8ae8eae999ceadebcda5b4909b81d45", - "reference": "2027be14f8ae8eae999ceadebcda5b4909b81d45", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9c46038cd4ed68952166cf7001b54eb539184ccb", + "reference": "9c46038cd4ed68952166cf7001b54eb539184ccb", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.2", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/console": "<5.4" + "symfony/console": "<6.4" }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", - "twig/twig": "^2.13|^3.0.4" + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.12" }, "bin": [ "Resources/bin/var-dump-server" @@ -6415,7 +6448,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.3.4" + "source": "https://github.com/symfony/var-dumper/tree/v7.2.6" }, "funding": [ { @@ -6431,20 +6464,20 @@ "type": "tidelift" } ], - "time": "2023-08-24T14:51:05+00:00" + "time": "2025-04-09T08:14:01+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -6473,7 +6506,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -6481,35 +6514,39 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2024-03-03T12:36:25+00:00" }, { "name": "twig/markdown-extra", - "version": "v3.7.1", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/markdown-extra.git", - "reference": "83dfa86a0379f784ea30bdb9c15a356b8aabf780" + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/83dfa86a0379f784ea30bdb9c15a356b8aabf780", - "reference": "83dfa86a0379f784ea30bdb9c15a356b8aabf780", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/f4616e1dd375209dacf6026f846e6b537d036ce4", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4", "shasum": "" }, "require": { - "php": ">=7.1.3", - "twig/twig": "^2.7|^3.0" + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" }, "require-dev": { - "erusev/parsedown": "^1.7", + "erusev/parsedown": "dev-master as 1.x-dev", "league/commonmark": "^1.0|^2.0", "league/html-to-markdown": "^4.8|^5.0", "michelf/php-markdown": "^1.8|^2.0", - "symfony/phpunit-bridge": "^5.4|^6.3" + "symfony/phpunit-bridge": "^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Twig\\Extra\\Markdown\\": "" }, @@ -6537,7 +6574,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/markdown-extra/tree/v3.7.1" + "source": "https://github.com/twigphp/markdown-extra/tree/v3.21.0" }, "funding": [ { @@ -6549,33 +6586,41 @@ "type": "tidelift" } ], - "time": "2023-07-29T15:34:56+00:00" + "time": "2025-01-31T20:45:36+00:00" }, { "name": "twig/twig", - "version": "v3.7.1", + "version": "v3.21.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { + "phpstan/phpstan": "^2.0", "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -6608,7 +6653,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.1" + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" }, "funding": [ { @@ -6620,7 +6665,7 @@ "type": "tidelift" } ], - "time": "2023-08-28T11:09:02+00:00" + "time": "2025-05-03T07:21:55+00:00" } ], "aliases": [], diff --git a/app/vendor/bin/sql-formatter b/app/vendor/bin/sql-formatter new file mode 100755 index 000000000..de69b8ade --- /dev/null +++ b/app/vendor/bin/sql-formatter @@ -0,0 +1,120 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/doctrine/sql-formatter/bin/sql-formatter'); + exit(0); + } +} + +include __DIR__ . '/..'.'/doctrine/sql-formatter/bin/sql-formatter'; diff --git a/app/vendor/bin/validate-json b/app/vendor/bin/validate-json index 5910c8159..d077db58b 100755 --- a/app/vendor/bin/validate-json +++ b/app/vendor/bin/validate-json @@ -108,7 +108,10 @@ if (PHP_VERSION_ID < 80000) { } } - if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { include("phpvfscomposer://" . __DIR__ . '/..'.'/justinrainbow/json-schema/bin/validate-json'); exit(0); } diff --git a/app/vendor/cakephp/cakephp/VERSION.txt b/app/vendor/cakephp/cakephp/VERSION.txt index 7a0262349..7bfb2d629 100644 --- a/app/vendor/cakephp/cakephp/VERSION.txt +++ b/app/vendor/cakephp/cakephp/VERSION.txt @@ -16,4 +16,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -4.4.17 +4.6.1 diff --git a/app/vendor/cakephp/cakephp/composer.json b/app/vendor/cakephp/cakephp/composer.json index 278f11070..0060696c6 100644 --- a/app/vendor/cakephp/cakephp/composer.json +++ b/app/vendor/cakephp/cakephp/composer.json @@ -22,11 +22,11 @@ } ], "require": { - "php": ">=7.4.0", + "php": ">=7.4.0,<9", "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", - "cakephp/chronos": "^2.2", + "cakephp/chronos": "^2.4.0-RC2", "composer/ca-bundle": "^1.2", "laminas/laminas-diactoros": "^2.2.2", "laminas/laminas-httphandlerrunner": "^1.1 || ^2.0", @@ -58,7 +58,7 @@ "require-dev": { "cakephp/cakephp-codesniffer": "^4.5", "mikey179/vfsstream": "^1.6.10", - "paragonie/csp-builder": "^2.3", + "paragonie/csp-builder": "^2.3 || ^3.0", "phpunit/phpunit": "^8.5 || ^9.3" }, "suggest": { @@ -88,6 +88,7 @@ }, "files": [ "src/Core/functions.php", + "src/Error/functions.php", "src/Collection/functions.php", "src/I18n/functions.php", "src/Routing/functions.php", diff --git a/app/vendor/cakephp/cakephp/src/Cache/Cache.php b/app/vendor/cakephp/cakephp/src/Cache/Cache.php index 0c8d8d37f..b91032291 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Cache.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Cache.php @@ -17,8 +17,11 @@ namespace Cake\Cache; use Cake\Cache\Engine\NullEngine; +use Cake\Cache\Exception\CacheWriteException; +use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\StaticConfigTrait; use RuntimeException; +use function Cake\Core\deprecationWarning; /** * Cache provides a consistent interface to Caching in your application. It allows you @@ -136,7 +139,7 @@ public static function setRegistry(CacheRegistry $registry): void * Finds and builds the instance of the required engine class. * * @param string $name Name of the config array that needs an engine instance built - * @throws \Cake\Cache\InvalidArgumentException When a cache engine cannot be created. + * @throws \Cake\Cache\Exception\InvalidArgumentException When a cache engine cannot be created. * @throws \RuntimeException If loading of the engine failed. * @return void */ @@ -265,15 +268,12 @@ public static function write(string $key, $value, string $config = 'default'): b $backend = static::pool($config); $success = $backend->set($key, $value); if ($success === false && $value !== '') { - trigger_error( - sprintf( - "%s cache was unable to write '%s' to %s cache", - $config, - $key, - get_class($backend) - ), - E_USER_WARNING - ); + throw new CacheWriteException(sprintf( + "%s cache was unable to write '%s' to %s cache", + $config, + $key, + get_class($backend) + )); } return $success; @@ -299,7 +299,7 @@ public static function write(string $key, $value, string $config = 'default'): b * @param iterable $data An array or Traversable of data to be stored in the cache * @param string $config Optional string configuration name to write to. Defaults to 'default' * @return bool True on success, false on failure - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function writeMany(iterable $data, string $config = 'default'): bool { @@ -354,7 +354,7 @@ public static function read(string $key, string $config = 'default') * @param string $config optional name of the configuration to use. Defaults to 'default' * @return iterable An array containing, for each of the given $keys, * the cached data or false if cached data could not be retrieved. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function readMany(iterable $keys, string $config = 'default'): iterable { @@ -369,7 +369,7 @@ public static function readMany(iterable $keys, string $config = 'default'): ite * @param string $config Optional string configuration name. Defaults to 'default' * @return int|false New value, or false if the data doesn't exist, is not integer, * or if there was an error fetching it. - * @throws \Cake\Cache\InvalidArgumentException When offset < 0 + * @throws \Cake\Cache\Exception\InvalidArgumentException When offset < 0 */ public static function increment(string $key, int $offset = 1, string $config = 'default') { @@ -388,7 +388,7 @@ public static function increment(string $key, int $offset = 1, string $config = * @param string $config Optional string configuration name. Defaults to 'default' * @return int|false New value, or false if the data doesn't exist, is not integer, * or if there was an error fetching it - * @throws \Cake\Cache\InvalidArgumentException when offset < 0 + * @throws \Cake\Cache\Exception\InvalidArgumentException when offset < 0 */ public static function decrement(string $key, int $offset = 1, string $config = 'default') { @@ -445,7 +445,7 @@ public static function delete(string $key, string $config = 'default'): bool * @param iterable $keys Array or Traversable of cache keys to be deleted * @param string $config name of the configuration to use. Defaults to 'default' * @return bool True on success, false on failure. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function deleteMany(iterable $keys, string $config = 'default'): bool { @@ -505,7 +505,7 @@ public static function clearGroup(string $group, string $config = 'default'): bo * * @param string|null $group Group name or null to retrieve all group mappings * @return array Map of group and all configuration that has the same group - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function groupConfigs(?string $group = null): array { diff --git a/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php b/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php index da5bcc719..b37fc672f 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php @@ -16,10 +16,12 @@ */ namespace Cake\Cache; +use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\InstanceConfigTrait; use DateInterval; use DateTime; use Psr\SimpleCache\CacheInterface; +use function Cake\Core\triggerWarning; /** * Storage engine for CakePHP caching @@ -96,7 +98,7 @@ public function init(array $config = []): bool * * @param string $key Key to check. * @return void - * @throws \Cake\Cache\InvalidArgumentException When the key is not valid. + * @throws \Cake\Cache\Exception\InvalidArgumentException When the key is not valid. */ protected function ensureValidKey($key): void { @@ -111,7 +113,7 @@ protected function ensureValidKey($key): void * @param iterable $iterable The iterable to check. * @param string $check Whether to check keys or values. * @return void - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ protected function ensureValidType($iterable, string $check = self::CHECK_VALUE): void { @@ -137,7 +139,7 @@ protected function ensureValidType($iterable, string $check = self::CHECK_VALUE) * @param iterable $keys A list of keys that can obtained in a single operation. * @param mixed $default Default value to return for keys that do not exist. * @return iterable A list of key value pairs. Cache keys that do not exist or are stale will have $default as value. - * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function getMultiple($keys, $default = null): iterable @@ -160,7 +162,7 @@ public function getMultiple($keys, $default = null): iterable * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * @return bool True on success and false on failure. - * @throws \Cake\Cache\InvalidArgumentException If $values is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $values is neither an array nor a Traversable, * or if any of the $values are not a legal value. */ public function setMultiple($values, $ttl = null): bool @@ -196,7 +198,7 @@ public function setMultiple($values, $ttl = null): bool * * @param iterable $keys A list of string-based keys to be deleted. * @return bool True if the items were successfully removed. False if there was an error. - * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function deleteMultiple($keys): bool @@ -223,7 +225,7 @@ public function deleteMultiple($keys): bool * * @param string $key The cache item key. * @return bool - * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. + * @throws \Cake\Cache\Exception\InvalidArgumentException If the $key string is not a legal value. */ public function has($key): bool { @@ -236,7 +238,7 @@ public function has($key): bool * @param string $key The unique key of this item in the cache. * @param mixed $default Default value to return if the key does not exist. * @return mixed The value of the item from the cache, or $default in case of cache miss. - * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. + * @throws \Cake\Cache\Exception\InvalidArgumentException If the $key string is not a legal value. */ abstract public function get($key, $default = null); @@ -249,7 +251,7 @@ abstract public function get($key, $default = null); * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * @return bool True on success and false on failure. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ abstract public function set($key, $value, $ttl = null): bool; @@ -337,7 +339,7 @@ public function groups(): array * * @param string $key the key passed over * @return string Prefixed key with potentially unsafe characters replaced. - * @throws \Cake\Cache\InvalidArgumentException If key's value is invalid. + * @throws \Cake\Cache\Exception\InvalidArgumentException If key's value is invalid. */ protected function _key($key): string { diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php index 35252b98e..9e786787a 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php @@ -50,6 +50,7 @@ class FileEngine extends CacheEngine * handy for deleting a complete group from cache. * - `lock` Used by FileCache. Should files be locked before writing to them? * - `mask` The mask used for created files + * - `dirMask` The mask used for created folders * - `path` Path to where cachefiles should be saved. Defaults to system's temp dir. * - `prefix` Prepended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. @@ -63,6 +64,7 @@ class FileEngine extends CacheEngine 'groups' => [], 'lock' => true, 'mask' => 0664, + 'dirMask' => 0770, 'path' => null, 'prefix' => 'cake_', 'serialize' => true, @@ -371,7 +373,7 @@ protected function _setKey(string $key, bool $createKey = false): bool $dir = $this->_config['path'] . $groups; if (!is_dir($dir)) { - mkdir($dir, 0775, true); + mkdir($dir, $this->_config['dirMask'], true); } $path = new SplFileInfo($dir . $key); @@ -418,7 +420,7 @@ protected function _active(): bool $success = true; if (!is_dir($path)) { // phpcs:disable - $success = @mkdir($path, 0775, true); + $success = @mkdir($path, $this->_config['dirMask'], true); // phpcs:enable } diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php index b714f5056..687987603 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php @@ -17,7 +17,7 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; -use InvalidArgumentException; +use Cake\Cache\Exception\InvalidArgumentException; use Memcached; use RuntimeException; @@ -98,7 +98,7 @@ class MemcachedEngine extends CacheEngine * * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not - * @throws \InvalidArgumentException When you try use authentication without + * @throws \Cake\Cache\Exception\InvalidArgumentException When you try use authentication without * Memcached compiled with SASL support */ public function init(array $config = []): bool @@ -199,7 +199,7 @@ public function init(array $config = []): bool * Settings the memcached instance * * @return void - * @throws \InvalidArgumentException When the Memcached extension is not built + * @throws \Cake\Cache\Exception\InvalidArgumentException When the Memcached extension is not built * with the desired serializer engine. */ protected function _setOptions(): void @@ -365,7 +365,7 @@ public function getMultiple($keys, $default = null): array $values = $this->_Memcached->getMulti($cacheKeys); $return = []; foreach ($cacheKeys as $original => $prefixed) { - $return[$original] = $values[$prefixed] ?? $default; + $return[$original] = array_key_exists($prefixed, $values) ? $values[$prefixed] : $default; } return $return; @@ -437,7 +437,7 @@ public function clear(): bool } foreach ($keys as $key) { - if (strpos($key, $this->_config['prefix']) === 0) { + if ($this->_config['prefix'] === '' || strpos($key, $this->_config['prefix']) === 0) { $this->_Memcached->delete($key); } } diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php index 4612a276b..89defe467 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php @@ -62,7 +62,13 @@ public function get($key, $default = null) */ public function getMultiple($keys, $default = null): iterable { - return []; + $result = []; + + foreach ($keys as $key) { + $result[$key] = $default; + } + + return $result; } /** diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php index dc90ef72f..cdd479fb2 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php @@ -45,6 +45,7 @@ class RedisEngine extends CacheEngine * - `password` Redis server password. * - `persistent` Connect to the Redis server with a persistent connection * - `port` port number to the Redis server. + * - `tls` connect to the Redis server using TLS. * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. * - `scanCount` Number of keys to ask for each scan (default: 10) @@ -61,6 +62,7 @@ class RedisEngine extends CacheEngine 'password' => false, 'persistent' => true, 'port' => 6379, + 'tls' => false, 'prefix' => 'cake_', 'host' => null, 'server' => '127.0.0.1', @@ -99,24 +101,29 @@ public function init(array $config = []): bool */ protected function _connect(): bool { + $tls = $this->_config['tls'] === true ? 'tls://' : ''; + + $map = [ + 'ssl_ca' => 'cafile', + 'ssl_key' => 'local_pk', + 'ssl_cert' => 'local_cert', + ]; + + $ssl = []; + foreach ($map as $key => $context) { + if (!empty($this->_config[$key])) { + $ssl[$context] = $this->_config[$key]; + } + } + try { - $this->_Redis = new Redis(); + $this->_Redis = $this->_createRedisInstance(); if (!empty($this->_config['unix_socket'])) { $return = $this->_Redis->connect($this->_config['unix_socket']); } elseif (empty($this->_config['persistent'])) { - $return = $this->_Redis->connect( - $this->_config['server'], - (int)$this->_config['port'], - (int)$this->_config['timeout'] - ); + $return = $this->_connectTransient($tls . $this->_config['server'], $ssl); } else { - $persistentId = $this->_config['port'] . $this->_config['timeout'] . $this->_config['database']; - $return = $this->_Redis->pconnect( - $this->_config['server'], - (int)$this->_config['port'], - (int)$this->_config['timeout'], - $persistentId - ); + $return = $this->_connectPersistent($tls . $this->_config['server'], $ssl); } } catch (RedisException $e) { if (class_exists(Log::class)) { @@ -135,6 +142,67 @@ protected function _connect(): bool return $return; } + /** + * Connects to a Redis server using a new connection. + * + * @param string $server Server to connect to. + * @param array $ssl SSL context options. + * @throws \RedisException + * @return bool True if Redis server was connected + */ + protected function _connectTransient($server, array $ssl): bool + { + if (empty($ssl)) { + return $this->_Redis->connect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'] + ); + } + + return $this->_Redis->connect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'], + null, + 0, + 0.0, + ['ssl' => $ssl] + ); + } + + /** + * Connects to a Redis server using a persistent connection. + * + * @param string $server Server to connect to. + * @param array $ssl SSL context options. + * @throws \RedisException + * @return bool True if Redis server was connected + */ + protected function _connectPersistent($server, array $ssl): bool + { + $persistentId = $this->_config['port'] . $this->_config['timeout'] . $this->_config['database']; + + if (empty($ssl)) { + return $this->_Redis->pconnect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'], + $persistentId + ); + } + + return $this->_Redis->pconnect( + $server, + (int)$this->_config['port'], + (int)$this->_config['timeout'], + $persistentId, + 0, + 0.0, + ['ssl' => $ssl] + ); + } + /** * Write data for key into cache. * @@ -394,6 +462,16 @@ protected function unserialize(string $value) return unserialize($value); } + /** + * Create new Redis instance. + * + * @return \Redis + */ + protected function _createRedisInstance(): Redis + { + return new Redis(); + } + /** * Disconnects from the redis server */ diff --git a/app/vendor/cakephp/cakephp/src/Cache/Exception/CacheWriteException.php b/app/vendor/cakephp/cakephp/src/Cache/Exception/CacheWriteException.php new file mode 100644 index 000000000..241ef6539 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Cache/Exception/CacheWriteException.php @@ -0,0 +1,27 @@ +> */ class Collection extends IteratorIterator implements CollectionInterface, Serializable { diff --git a/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php b/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php index 7e50cfced..1fcd3a1ab 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php +++ b/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php @@ -24,6 +24,8 @@ * Describes the methods a Collection should implement. A collection is an immutable * list of elements exposing a number of traversing and extracting method for * generating other collections. + * + * @template-extends \Iterator */ interface CollectionInterface extends Iterator, JsonSerializable { diff --git a/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php b/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php index 010b06a63..7cee96969 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php +++ b/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php @@ -591,14 +591,37 @@ public function combine($keyPath, $valuePath, $groupPath = null): CollectionInte $rowVal = $options['valuePath']; if (!$options['groupPath']) { - $mapReduce->emit($rowVal($value, $key), $rowKey($value, $key)); + $mapKey = $rowKey($value, $key); + if ($mapKey === null) { + throw new InvalidArgumentException( + 'Cannot index by path that does not exist or contains a null value. ' . + 'Use a callback to return a default value for that path.' + ); + } + + $mapReduce->emit($rowVal($value, $key), $mapKey); return null; } $key = $options['groupPath']($value, $key); + if ($key === null) { + throw new InvalidArgumentException( + 'Cannot group by path that does not exist or contains a null value. ' . + 'Use a callback to return a default value for that path.' + ); + } + + $mapKey = $rowKey($value, $key); + if ($mapKey === null) { + throw new InvalidArgumentException( + 'Cannot index by path that does not exist or contains a null value. ' . + 'Use a callback to return a default value for that path.' + ); + } + $mapReduce->emitIntermediate( - [$rowKey($value, $key) => $rowVal($value, $key)], + [$mapKey => $rowVal($value, $key)], $key ); }; diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php index 6e3048c7d..0ea3368fe 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php @@ -25,6 +25,8 @@ * like an iterator for the original passed data after each result has been * processed, thus offering a transparent wrapper for results coming from any * source. + * + * @template-implements \IteratorAggregate */ class MapReduce implements IteratorAggregate { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php index c60c39b2f..831bc46fa 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php @@ -23,6 +23,8 @@ /** * A type of collection that is aware of nested items and exposes methods to * check or retrieve them + * + * @template-implements \RecursiveIterator */ class NestIterator extends Collection implements RecursiveIterator { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php index ed940c1c4..53f5ceb79 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php @@ -23,6 +23,8 @@ * An iterator that can be used as an argument for other iterators that require * a RecursiveIterator but do not want children. This iterator will * always behave as having no nested items. + * + * @template-implements \RecursiveIterator */ class NoChildrenIterator extends Collection implements RecursiveIterator { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php index 49a28fe01..e8072db31 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php @@ -24,6 +24,8 @@ /** * A Recursive iterator used to flatten nested structures and also exposes * all Collection methods + * + * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> */ class TreeIterator extends RecursiveIteratorIterator implements CollectionInterface { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php index d509d471a..0942b0f18 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php @@ -24,6 +24,8 @@ /** * Iterator for flattening elements in a tree structure while adding some * visual markers for their relative position in the tree + * + * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> */ class TreePrinter extends RecursiveIteratorIterator implements CollectionInterface { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php index 017373ebc..db284c1aa 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php @@ -26,6 +26,8 @@ * * @internal * @see \Cake\Collection\Collection::unfold() + * @template-implements \RecursiveIterator + * @template-extends \IteratorIterator> */ class UnfoldIterator extends IteratorIterator implements RecursiveIterator { diff --git a/app/vendor/cakephp/cakephp/src/Collection/functions.php b/app/vendor/cakephp/cakephp/src/Collection/functions.php index 0440f10ff..b3bbfb9eb 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/functions.php +++ b/app/vendor/cakephp/cakephp/src/Collection/functions.php @@ -1,4 +1,5 @@ setDescription('Clear all data in a single cache group.'); + $parser->addArgument('group', [ + 'help' => 'The cache group to clear. For example, `cake cache clear_group mygroup` will clear ' . + 'all cache items belonging to group "mygroup".', + 'required' => true, + ]); + $parser->addArgument('config', [ + 'help' => 'Name of the configuration to use. Defaults to no value which clears all cache configurations.', + ]); + + return $parser; + } + + /** + * Clears the cache group + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $group = (string)$args->getArgument('group'); + try { + $groupConfigs = Cache::groupConfigs($group); + } catch (InvalidArgumentException $e) { + $io->error(sprintf('Cache group "%s" not found', $group)); + + return static::CODE_ERROR; + } + + $config = $args->getArgument('config'); + if ($config !== null && Cache::getConfig($config) === null) { + $io->error(sprintf('Cache config "%s" not found', $config)); + + return static::CODE_ERROR; + } + + foreach ($groupConfigs[$group] as $groupConfig) { + if ($config !== null && $config !== $groupConfig) { + continue; + } + + if (!Cache::clearGroup($group, $groupConfig)) { + $io->error(sprintf( + 'Error encountered clearing group "%s". Was unable to clear entries for "%s".', + $group, + $groupConfig + )); + $this->abort(); + } else { + $io->success(sprintf('Cache "%s" was cleared.', $groupConfig)); + } + } + + return static::CODE_SUCCESS; + } +} diff --git a/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php b/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php index 724783bcf..1b6a04252 100644 --- a/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php @@ -133,7 +133,7 @@ protected function _getPaths(ConsoleIo $io): void /** @psalm-suppress UndefinedConstant */ $defaultPaths = array_merge( [APP], - App::path('templates'), + array_values(App::path('templates')), ['D'] // This is required to break the loop below ); $defaultPathIndex = 0; @@ -217,7 +217,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int . 'locales' . DIRECTORY_SEPARATOR; } else { $message = "What is the path you would like to output?\n[Q]uit"; - $localePaths = App::path('locales'); + $localePaths = array_values(App::path('locales')); if (!$localePaths) { $localePaths[] = ROOT . 'resources' . DIRECTORY_SEPARATOR . 'locales'; } diff --git a/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php b/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php index ff2806888..39bbf5b83 100644 --- a/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php @@ -56,7 +56,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int return static::CODE_ERROR; } - $paths = App::path('locales'); + $paths = array_values(App::path('locales')); if ($args->hasOption('plugin')) { $plugin = Inflector::camelize((string)$args->getOption('plugin')); $paths = [Plugin::path($plugin) . 'resources' . DIRECTORY_SEPARATOR . 'locales' . DIRECTORY_SEPARATOR]; @@ -66,7 +66,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $sourceFolder = rtrim($response, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; $targetFolder = $sourceFolder . $language . DIRECTORY_SEPARATOR; if (!is_dir($targetFolder)) { - mkdir($targetFolder, 0775, true); + mkdir($targetFolder, 0770, true); } $count = 0; diff --git a/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php b/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php index 69f1203a0..8019638f9 100644 --- a/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php @@ -21,6 +21,7 @@ use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; +use function Cake\Core\env; /** * built-in Server command diff --git a/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php b/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php index c927ccf80..b9b13e47a 100644 --- a/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php +++ b/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php @@ -21,6 +21,7 @@ use Cake\Utility\Inflector; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\getTypeName; /** * Base class for console commands. @@ -238,7 +239,7 @@ protected function setOutputLevel(Arguments $args, ConsoleIo $io): void abstract public function execute(Arguments $args, ConsoleIo $io); /** - * Halt the the current process with a StopException. + * Halt the current process with a StopException. * * @param int $code The exit code to use. * @throws \Cake\Console\Exception\StopException diff --git a/app/vendor/cakephp/cakephp/src/Console/Command.php b/app/vendor/cakephp/cakephp/src/Console/Command.php index 9494b024a..5062c8ddc 100644 --- a/app/vendor/cakephp/cakephp/src/Console/Command.php +++ b/app/vendor/cakephp/cakephp/src/Console/Command.php @@ -1,7 +1,9 @@ > */ class CommandCollection implements IteratorAggregate, Countable { @@ -127,7 +129,7 @@ public function has(string $name): bool * Get the target for a command. * * @param string $name The named shell. - * @return \Cake\Console\CommandInterface|\Cake\Console\Shell|string Either the command class or an instance. + * @return \Cake\Console\CommandInterface|\Cake\Console\Shell|class-string<\Cake\Console\CommandInterface> Either the command class or an instance. * @throws \InvalidArgumentException when unknown commands are fetched. * @psalm-return \Cake\Console\CommandInterface|\Cake\Console\Shell|class-string */ @@ -144,7 +146,7 @@ public function get(string $name) * Implementation of IteratorAggregate. * * @return \Traversable - * @psalm-return \Traversable + * @psalm-return \Traversable)> */ public function getIterator(): Traversable { diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php index cac0d22f5..27fcf22f8 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php @@ -1,7 +1,10 @@ $choices Valid choices for this option. + * @param string|null $default The default value for this argument. */ - public function __construct($name, $help = '', $required = false, $choices = []) + public function __construct($name, $help = '', $required = false, $choices = [], $default = null) { if (is_array($name) && isset($name['name'])) { foreach ($name as $key => $value) { @@ -75,6 +83,7 @@ public function __construct($name, $help = '', $required = false, $choices = []) $this->_help = $help; $this->_required = $required; $this->_choices = $choices; + $this->_default = $default; } } @@ -119,6 +128,9 @@ public function help(int $width = 0): string if ($this->_choices) { $optional .= sprintf(' (choices: %s)', implode('|', $this->_choices)); } + if ($this->_default !== null) { + $optional .= sprintf(' default: "%s"', $this->_default); + } return sprintf('%s%s%s', $name, $this->_help, $optional); } @@ -142,6 +154,16 @@ public function usage(): string return $name; } + /** + * Get the default value for this argument + * + * @return string|null + */ + public function defaultValue() + { + return $this->_default; + } + /** * Check if this argument is a required argument * @@ -194,6 +216,9 @@ public function xml(SimpleXMLElement $parent): SimpleXMLElement foreach ($this->_choices as $valid) { $choices->addChild('choice', $valid); } + if ($this->_default !== null) { + $option->addAttribute('default', $this->_default); + } return $parent; } diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php index 583873800..4e5e9c7ea 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php @@ -207,7 +207,7 @@ public function out($message = '', int $newlines = 1, int $level = self::NORMAL) } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -225,7 +225,7 @@ public function info($message, int $newlines = 1, int $level = self::NORMAL): ?i } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -243,7 +243,7 @@ public function comment($message, int $newlines = 1, int $level = self::NORMAL): } /** - * Convenience method for err() that wraps message between tag + * Convenience method for err() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -259,7 +259,7 @@ public function warning($message, int $newlines = 1): int } /** - * Convenience method for err() that wraps message between tag + * Convenience method for err() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -275,7 +275,7 @@ public function error($message, int $newlines = 1): int } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php index b20775a1d..eee1c8b4f 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php @@ -691,10 +691,23 @@ public function parse(array $argv, ?ConsoleIo $io = null): array /** @psalm-suppress PossiblyNullReference */ return $this->_subcommands[$command]->parser()->parse($argv, $io); } + $params = $args = []; $this->_tokens = $argv; + + $afterDoubleDash = false; while (($token = array_shift($this->_tokens)) !== null) { $token = (string)$token; + if ($token === '--') { + $afterDoubleDash = true; + continue; + } + if ($afterDoubleDash) { + // only positional arguments after -- + $args = $this->_parseArg($token, $args); + continue; + } + if (isset($this->_subcommands[$token])) { continue; } @@ -712,10 +725,15 @@ public function parse(array $argv, ?ConsoleIo $io = null): array } foreach ($this->_args as $i => $arg) { - if ($arg->isRequired() && !isset($args[$i])) { - throw new ConsoleException( - sprintf('Missing required argument. The `%s` argument is required.', $arg->name()) - ); + if (!isset($args[$i])) { + if ($arg->isRequired()) { + throw new ConsoleException( + sprintf('Missing required argument. The `%s` argument is required.', $arg->name()) + ); + } + if ($arg->defaultValue() !== null) { + $args[$i] = $arg->defaultValue(); + } } } foreach ($this->_options as $option) { diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php index c11101875..4c7ea902a 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php @@ -16,7 +16,9 @@ */ namespace Cake\Console; +use Cake\Console\Exception\ConsoleException; use InvalidArgumentException; +use function Cake\Core\env; /** * Object wrapper for outputting information from a shell application. @@ -160,11 +162,20 @@ class ConsoleOutput * Checks for a pretty console environment. Ansicon and ConEmu allows * pretty consoles on Windows, and is supported. * - * @param string $stream The identifier of the stream to write output to. + * @param string|resource $stream The identifier of the stream to write output to. + * @throws \Cake\Console\Exception\ConsoleException If the given stream is not a valid resource. */ - public function __construct(string $stream = 'php://stdout') + public function __construct($stream = 'php://stdout') { - $this->_output = fopen($stream, 'wb'); + if (is_string($stream)) { + $stream = fopen($stream, 'wb'); + } + + if (!is_resource($stream)) { + throw new ConsoleException('Invalid stream in constructor. It is not a valid resource.'); + } + + $this->_output = $stream; if ( ( diff --git a/app/vendor/cakephp/cakephp/src/Console/Shell.php b/app/vendor/cakephp/cakephp/src/Console/Shell.php index 636216766..46bdda200 100644 --- a/app/vendor/cakephp/cakephp/src/Console/Shell.php +++ b/app/vendor/cakephp/cakephp/src/Console/Shell.php @@ -31,6 +31,7 @@ use ReflectionException; use ReflectionMethod; use RuntimeException; +use function Cake\Core\namespaceSplit; /** * Base class for command-line utilities for automating programmer chores. @@ -719,7 +720,7 @@ public function err($message, int $newlines = 1): int } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -733,7 +734,7 @@ public function info($message, int $newlines = 1, int $level = Shell::NORMAL): ? } /** - * Convenience method for err() that wraps message between tag + * Convenience method for err() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -746,7 +747,7 @@ public function warn($message, int $newlines = 1): int } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append diff --git a/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php b/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php index 2075784b0..a8615a168 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php +++ b/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php @@ -24,6 +24,7 @@ use Cake\Log\Log; use Cake\Shell\Task\CommandTask; use Cake\Utility\Inflector; +use function Cake\Core\pluginSplit; /** * Shell dispatcher handles dispatching CLI commands. diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php index f5f756fc7..b10d2cd98 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php @@ -343,3 +343,10 @@ protected function commandStringToArgs(string $command): array return $argv; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\ConsoleIntegrationTestTrait', + 'Cake\TestSuite\ConsoleIntegrationTestTrait' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php index 8ea9d2619..f9f87322d 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php @@ -46,3 +46,10 @@ public function __construct(array $contents, string $output) $this->output = $output; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsBase', + 'Cake\TestSuite\Constraint\Console\ContentsBase' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php index 5dc3942e4..82747a782 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php @@ -43,3 +43,10 @@ public function toString(): string return sprintf('is in %s,' . PHP_EOL . 'actual result:' . PHP_EOL, $this->output) . $this->contents; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsContain', + 'Cake\TestSuite\Constraint\Console\ContentsContain' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php index a1b9edd08..583abbfb5 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php @@ -59,3 +59,10 @@ public function failureDescription($other): string return '`' . $this->exporter()->shortenedExport($other) . '` ' . $this->toString(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsContainRow', + 'Cake\TestSuite\Constraint\Console\ContentsContainRow' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php index 015d68bbc..6cae114e3 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php @@ -54,3 +54,10 @@ protected function failureDescription($other): string return $this->toString(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsEmpty', + 'Cake\TestSuite\Constraint\Console\ContentsEmpty' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php index 47855c520..c8a666c13 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php @@ -43,3 +43,10 @@ public function toString(): string return sprintf('is not in %s', $this->output); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsNotContain', + 'Cake\TestSuite\Constraint\Console\ContentsNotContain' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php index e3a3fb6c7..a715b95d6 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php @@ -52,3 +52,10 @@ public function failureDescription($other): string return '`' . $other . '` ' . $this->toString(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsRegExp', + 'Cake\TestSuite\Constraint\Console\ContentsRegExp' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php index 4e7f01edb..da3f46a5d 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php @@ -60,3 +60,10 @@ public function toString(): string return sprintf('matches exit code %s', $this->exitCode ?? 'null'); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ExitCode', + 'Cake\TestSuite\Constraint\Console\ExitCode' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php index 8cbb5542a..d1ec2c74d 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php @@ -37,3 +37,10 @@ public function run(array $argv, ?ConsoleIo $io = null): int return $dispatcher->dispatch(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\LegacyCommandRunner', + 'Cake\TestSuite\LegacyCommandRunner' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php index 59caba325..cc9fde4da 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php @@ -18,6 +18,7 @@ use Cake\Console\ConsoleIo; use Cake\Console\Shell; use Cake\Console\ShellDispatcher; +use function Cake\Core\pluginSplit; /** * Allows injecting mock IO into shells @@ -62,3 +63,10 @@ protected function _createShell(string $className, string $shortName): Shell return $instance; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\LegacyShellDispatcher', + 'Cake\TestSuite\LegacyShellDispatcher' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php index a76d36f63..9b58c4659 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php @@ -35,5 +35,8 @@ public function setQuestion($question) } // phpcs:disable -class_alias(MissingConsoleInputException::class, 'Cake\TestSuite\Stub\MissingConsoleInputException'); +class_alias( + 'Cake\Console\TestSuite\MissingConsoleInputException', + 'Cake\TestSuite\Stub\MissingConsoleInputException' +); // phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php index 96a83198f..cd968194a 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php @@ -86,3 +86,10 @@ public function dataAvailable($timeout = 0): bool return true; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\StubConsoleInput', + 'Cake\TestSuite\Stub\ConsoleInput' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php index 280ea3e7d..46b234237 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php @@ -82,3 +82,10 @@ public function output(): string return implode("\n", $this->_out); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\StubConsoleOutput', + 'Cake\TestSuite\Stub\ConsoleOutput' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component.php b/app/vendor/cakephp/cakephp/src/Controller/Component.php index 1ebafbd59..9cdc87ad1 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component.php @@ -19,6 +19,7 @@ use Cake\Core\InstanceConfigTrait; use Cake\Event\EventListenerInterface; use Cake\Log\LogTrait; +use function Cake\Core\deprecationWarning; /** * Base class for an individual Component. Components provide reusable bits of diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php index d9b0a59e5..851117c75 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php @@ -31,6 +31,7 @@ use Cake\Http\ServerRequest; use Cake\Routing\Router; use Cake\Utility\Hash; +use function Cake\I18n\__d; /** * Authentication control component class. diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php index 947403dca..54a2fd99a 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php @@ -67,6 +67,20 @@ class FormProtectionComponent extends Component 'validationFailureCallback' => null, ]; + /** + * Get Session id for FormProtector + * Must be the same as in FormHelper + * + * @return string + */ + protected function _getSessionId(): string + { + $session = $this->getController()->getRequest()->getSession(); + $session->start(); + + return $session->id(); + } + /** * Component startup. * @@ -86,12 +100,11 @@ public function startup(EventInterface $event): ?Response && $hasData && $this->_config['validate'] ) { - $session = $request->getSession(); - $session->start(); + $sessionId = $this->_getSessionId(); $url = Router::url($request->getRequestTarget()); $formProtector = new FormProtector($this->_config); - $isValid = $formProtector->validate($data, $url, $session->id()); + $isValid = $formProtector->validate($data, $url, $sessionId); if (!$isValid) { return $this->validationFailure($formProtector); diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php index 85e27729a..07dc6352e 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php @@ -24,6 +24,7 @@ use Cake\Http\Exception\NotFoundException; use InvalidArgumentException; use UnexpectedValueException; +use function Cake\Core\deprecationWarning; /** * This component is used to handle automatic model data pagination. The primary way to use this diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php index 1b84ba258..6938d0cb4 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php @@ -209,7 +209,7 @@ protected function _secureRequired(Controller $controller): void ($requireSecure[0] === '*' || in_array($this->_action, $requireSecure, true) ) && - !$controller->getRequest()->is('ssl') + !$controller->getRequest()->is('https') ) { throw new SecurityException( 'Request is not SSL and the action is required to be secure' diff --git a/app/vendor/cakephp/cakephp/src/Controller/Controller.php b/app/vendor/cakephp/cakephp/src/Controller/Controller.php index 623214fd6..5d2831ff5 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Controller.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Controller.php @@ -44,6 +44,11 @@ use ReflectionMethod; use RuntimeException; use UnexpectedValueException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\Core\namespaceSplit; +use function Cake\Core\pluginSplit; +use function Cake\Core\triggerWarning; /** * Application controller class for organization of business logic. @@ -91,6 +96,7 @@ * @property \Cake\Controller\Component\RequestHandlerComponent $RequestHandler * @property \Cake\Controller\Component\SecurityComponent $Security * @property \Cake\Controller\Component\AuthComponent $Auth + * @property \Cake\Controller\Component\CheckHttpCacheComponent $CheckHttpCache * @link https://book.cakephp.org/4/en/controllers.html */ #[\AllowDynamicProperties] @@ -170,6 +176,13 @@ class Controller implements EventListenerInterface, EventDispatcherInterface */ protected $middlewares = []; + /** + * View classes for content negotiation. + * + * @var array + */ + protected $viewClasses = []; + /** * Constructor. * @@ -320,7 +333,7 @@ public function __get(string $name) } if ($class === $name) { - return $this->loadModel(); + return $this->fetchModel(); } } @@ -684,10 +697,14 @@ public function redirect($url, int $status = 302): ?Response { $this->autoRender = false; - if ($status) { - $this->response = $this->response->withStatus($status); + if ($status < 300 || $status > 399) { + throw new InvalidArgumentException( + sprintf('Invalid status code `%s`. It should be within the range ' . + '`300` - `399` for redirect responses.', $status) + ); } + $this->response = $this->response->withStatus($status); $event = $this->dispatchEvent('Controller.beforeRedirect', [$url, $this->response]); if ($event->getResult() instanceof Response) { return $this->response = $event->getResult(); @@ -787,7 +804,25 @@ public function render(?string $template = null, ?string $layout = null): Respon */ public function viewClasses(): array { - return []; + return $this->viewClasses; + } + + /** + * Add View classes this controller can perform content negotiation with. + * + * Each view class must implement the `getContentType()` hook method + * to participate in negotiation. + * + * @param array $viewClasses View classes list. + * @return $this + * @see Cake\Http\ContentTypeNegotiation + * @since 4.5.0 + */ + public function addViewClasses(array $viewClasses) + { + $this->viewClasses = array_merge($this->viewClasses, $viewClasses); + + return $this; } /** diff --git a/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php b/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php index 34b8c18a7..88e776c4b 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php +++ b/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php @@ -32,6 +32,7 @@ use ReflectionClass; use ReflectionFunction; use ReflectionNamedType; +use function Cake\Core\deprecationWarning; /** * Factory method for building controllers for request. @@ -105,7 +106,7 @@ public function invoke($controller): ResponseInterface $middlewares = $controller->getMiddleware(); if ($middlewares) { - $middlewareQueue = new MiddlewareQueue($middlewares); + $middlewareQueue = new MiddlewareQueue($middlewares, $this->container); $runner = new Runner(); return $runner->run($middlewareQueue, $controller->getRequest(), $this); @@ -159,17 +160,6 @@ protected function getActionArgs(Closure $action, array $passedParams): array $function = new ReflectionFunction($action); foreach ($function->getParameters() as $parameter) { $type = $parameter->getType(); - if ($type && !$type instanceof ReflectionNamedType) { - // Only single types are supported - throw new InvalidParameterException([ - 'template' => 'unsupported_type', - 'parameter' => $parameter->getName(), - 'controller' => $this->controller->getName(), - 'action' => $this->controller->getRequest()->getParam('action'), - 'prefix' => $this->controller->getRequest()->getParam('prefix'), - 'plugin' => $this->controller->getRequest()->getParam('plugin'), - ]); - } // Check for dependency injection for classes if ($type instanceof ReflectionNamedType && !$type->isBuiltin()) { @@ -354,3 +344,10 @@ protected function missingController(ServerRequest $request) ]); } } + +// phpcs:disable +class_alias( + 'Cake\Controller\ControllerFactory', + 'Cake\Http\ControllerFactory' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php b/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php index 34931c895..79bcdea49 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php +++ b/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php @@ -18,6 +18,7 @@ use Cake\Core\Exception\CakeException; use Cake\Core\Plugin; +use function Cake\Core\pluginSplit; /** * Trait providing utility methods for file based config engines. diff --git a/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php b/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php index 82ef43738..43f885a81 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php +++ b/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php @@ -16,6 +16,7 @@ use RuntimeException; use Throwable; +use function Cake\Core\deprecationWarning; /** * Base class that all CakePHP Exceptions extend. @@ -115,5 +116,8 @@ public function responseHeader($header = null, $value = null): ?array } // phpcs:disable -class_exists('Cake\Core\Exception\Exception'); +class_alias( + 'Cake\Core\Exception\CakeException', + 'Cake\Core\Exception\Exception' +); // phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php b/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php index fb5d49fb2..bd93c509e 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php +++ b/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php @@ -1,6 +1,8 @@ */ abstract class ObjectRegistry implements Countable, IteratorAggregate { @@ -336,7 +337,6 @@ public function reset() * @param object $object instance to store in the registry * @return $this * @psalm-param TObject $object - * @psalm-suppress MoreSpecificReturnType */ public function set(string $name, object $object) { @@ -351,7 +351,6 @@ public function set(string $name, object $object) } $this->_loaded[$objName] = $object; - /** @psalm-suppress LessSpecificReturnStatement */ return $this; } @@ -362,7 +361,6 @@ public function set(string $name, object $object) * * @param string $name The name of the object to remove from the registry. * @return $this - * @psalm-suppress MoreSpecificReturnType */ public function unload(string $name) { @@ -377,7 +375,6 @@ public function unload(string $name) } unset($this->_loaded[$name]); - /** @psalm-suppress LessSpecificReturnStatement */ return $this; } diff --git a/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php b/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php index 1862d6e43..a9fc4a191 100644 --- a/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php +++ b/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php @@ -15,6 +15,7 @@ */ namespace Cake\Core; +use Cake\Core\Exception\CakeException; use Cake\Core\Exception\MissingPluginException; use Countable; use Generator; @@ -34,6 +35,8 @@ * * While its implementation supported nested iteration it does not * support using `continue` or `break` inside loops. + * + * @template-implements \Iterator */ class PluginCollection implements Iterator, Countable { @@ -232,6 +235,10 @@ public function get(string $name): PluginInterface */ public function create(string $name, array $config = []): PluginInterface { + if ($name === '') { + throw new CakeException('Cannot create a plugin with empty name'); + } + if (strpos($name, '\\') !== false) { /** @var \Cake\Core\PluginInterface */ return new $name($config); diff --git a/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php b/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php index 909ade79f..9c6ae1e05 100644 --- a/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php +++ b/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php @@ -172,3 +172,10 @@ public function cleanupContainer(): void $this->containerServices = []; } } + +// phpcs:disable +class_alias( + 'Cake\Core\TestSuite\ContainerStubTrait', + 'Cake\TestSuite\ContainerStubTrait' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Core/functions.php b/app/vendor/cakephp/cakephp/src/Core/functions.php index f938d8817..af2d2b6c3 100644 --- a/app/vendor/cakephp/cakephp/src/Core/functions.php +++ b/app/vendor/cakephp/cakephp/src/Core/functions.php @@ -11,20 +11,13 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @link https://cakephp.org CakePHP(tm) Project - * @since 3.0.0 + * @since 4.5.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ +// phpcs:disable PSR1.Files.SideEffects +namespace Cake\Core; -use Cake\Core\Configure; - -if (!defined('DS')) { - /** - * Defines DS as short form of DIRECTORY_SEPARATOR. - */ - define('DS', DIRECTORY_SEPARATOR); -} - -if (!function_exists('h')) { +if (!function_exists('Cake\Core\h')) { /** * Convenience method for htmlspecialchars. * @@ -66,10 +59,9 @@ function h($text, bool $double = true, ?string $charset = null) return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, $charset ?: $defaultCharset, $double); } - } -if (!function_exists('pluginSplit')) { +if (!function_exists('Cake\Core\pluginSplit')) { /** * Splits a dot syntax plugin name into its plugin and class name. * If $name does not have a dot, then index 0 will be null. @@ -94,16 +86,15 @@ function pluginSplit(string $name, bool $dotAppend = false, ?string $plugin = nu $parts[0] .= '.'; } - /** @psalm-var array{string, string}*/ + /** @psalm-var array{string, string} */ return $parts; } return [$plugin, $name]; } - } -if (!function_exists('namespaceSplit')) { +if (!function_exists('Cake\Core\namespaceSplit')) { /** * Split the namespace from the classname. * @@ -121,10 +112,9 @@ function namespaceSplit(string $class): array return [substr($class, 0, $pos), substr($class, $pos + 1)]; } - } -if (!function_exists('pr')) { +if (!function_exists('Cake\Core\pr')) { /** * print_r() convenience function. * @@ -149,10 +139,9 @@ function pr($var) return $var; } - } -if (!function_exists('pj')) { +if (!function_exists('Cake\Core\pj')) { /** * JSON pretty print convenience function. * @@ -177,10 +166,9 @@ function pj($var) return $var; } - } -if (!function_exists('env')) { +if (!function_exists('Cake\Core\env')) { /** * Gets an environment variable from available sources, and provides emulation * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on @@ -242,10 +230,9 @@ function env(string $key, $default = null) return $default; } - } -if (!function_exists('triggerWarning')) { +if (!function_exists('Cake\Core\triggerWarning')) { /** * Triggers an E_USER_WARNING. * @@ -269,7 +256,7 @@ function triggerWarning(string $message): void } } -if (!function_exists('deprecationWarning')) { +if (!function_exists('Cake\Core\deprecationWarning')) { /** * Helper method for outputting deprecation warnings * @@ -294,7 +281,11 @@ function deprecationWarning(string $message, int $stackFrame = 1): void if (defined('ROOT')) { $root = ROOT; } - $relative = str_replace(DIRECTORY_SEPARATOR, '/', substr($frame['file'], strlen($root) + 1)); + $relative = str_replace( + DIRECTORY_SEPARATOR, + '/', + substr($frame['file'], strlen($root) + 1) + ); $patterns = (array)Configure::read('Error.ignoredDeprecationPaths'); foreach ($patterns as $pattern) { $pattern = str_replace(DIRECTORY_SEPARATOR, '/', $pattern); @@ -304,8 +295,7 @@ function deprecationWarning(string $message, int $stackFrame = 1): void } $message = sprintf( - "%s\n%s, line: %s\n" . - 'You can disable all deprecation warnings by setting `Error.errorLevel` to ' . + "%s\n%s, line: %s\n" . 'You can disable all deprecation warnings by setting `Error.errorLevel` to ' . '`E_ALL & ~E_USER_DEPRECATED`. Adding `%s` to `Error.ignoredDeprecationPaths` ' . 'in your `config/app.php` config will mute deprecations from that file only.', $message, @@ -329,7 +319,7 @@ function deprecationWarning(string $message, int $stackFrame = 1): void } } -if (!function_exists('getTypeName')) { +if (!function_exists('Cake\Core\getTypeName')) { /** * Returns the objects class or var type of it's not an object * @@ -341,3 +331,10 @@ function getTypeName($var): string return is_object($var) ? get_class($var) : gettype($var); } } + +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; +} diff --git a/app/vendor/cakephp/cakephp/src/Core/functions_global.php b/app/vendor/cakephp/cakephp/src/Core/functions_global.php new file mode 100644 index 000000000..bb2a71478 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Core/functions_global.php @@ -0,0 +1,190 @@ + plugin name, 1 => class name. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#pluginSplit + * @psalm-return array{string|null, string} + */ + function pluginSplit(string $name, bool $dotAppend = false, ?string $plugin = null): array + { + return cakePluginSplit($name, $dotAppend, $plugin); + } +} + +if (!function_exists('namespaceSplit')) { + /** + * Split the namespace from the classname. + * + * Commonly used like `list($namespace, $className) = namespaceSplit($class);`. + * + * @param string $class The full class name, ie `Cake\Core\App`. + * @return array Array with 2 indexes. 0 => namespace, 1 => classname. + */ + function namespaceSplit(string $class): array + { + return cakeNamespaceSplit($class); + } +} + +if (!function_exists('pr')) { + /** + * print_r() convenience function. + * + * In terminals this will act similar to using print_r() directly, when not run on CLI + * print_r() will also wrap `
` tags around the output of given variable. Similar to debug().
+     *
+     * This function returns the same variable that was passed.
+     *
+     * @param mixed $var Variable to print out.
+     * @return mixed the same $var that was passed to this function
+     * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#pr
+     * @see debug()
+     */
+    function pr($var)
+    {
+        return cakePr($var);
+    }
+}
+
+if (!function_exists('pj')) {
+    /**
+     * JSON pretty print convenience function.
+     *
+     * In terminals this will act similar to using json_encode() with JSON_PRETTY_PRINT directly, when not run on CLI
+     * will also wrap `
` tags around the output of given variable. Similar to pr().
+     *
+     * This function returns the same variable that was passed.
+     *
+     * @param mixed $var Variable to print out.
+     * @return mixed the same $var that was passed to this function
+     * @see pr()
+     * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#pj
+     */
+    function pj($var)
+    {
+        return cakePj($var);
+    }
+}
+
+if (!function_exists('env')) {
+    /**
+     * Gets an environment variable from available sources, and provides emulation
+     * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
+     * IIS, or SCRIPT_NAME in CGI mode). Also exposes some additional custom
+     * environment information.
+     *
+     * @param string $key Environment variable name.
+     * @param string|bool|null $default Specify a default value in case the environment variable is not defined.
+     * @return string|bool|null Environment variable setting.
+     * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#env
+     */
+    function env(string $key, $default = null)
+    {
+        return cakeEnv($key, $default);
+    }
+}
+
+if (!function_exists('triggerWarning')) {
+    /**
+     * Triggers an E_USER_WARNING.
+     *
+     * @param string $message The warning message.
+     * @return void
+     */
+    function triggerWarning(string $message): void
+    {
+        cakeTriggerWarning($message);
+    }
+}
+
+if (!function_exists('deprecationWarning')) {
+    /**
+     * Helper method for outputting deprecation warnings
+     *
+     * @param string $message The message to output as a deprecation warning.
+     * @param int $stackFrame The stack frame to include in the error. Defaults to 1
+     *   as that should point to application/plugin code.
+     * @return void
+     */
+    function deprecationWarning(string $message, int $stackFrame = 1): void
+    {
+        cakeDeprecationWarning($message, $stackFrame + 1);
+    }
+}
+
+if (!function_exists('getTypeName')) {
+    /**
+     * Returns the objects class or var type of it's not an object
+     *
+     * @param mixed $var Variable to check
+     * @return string Returns the class name or variable type
+     */
+    function getTypeName($var): string
+    {
+        return cakeGetTypeName($var);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Connection.php b/app/vendor/cakephp/cakephp/src/Database/Connection.php
index 92a54ae8d..83777d723 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Connection.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Connection.php
@@ -26,6 +26,10 @@
 use Cake\Database\Log\LoggedQuery;
 use Cake\Database\Log\LoggingStatement;
 use Cake\Database\Log\QueryLogger;
+use Cake\Database\Query\DeleteQuery;
+use Cake\Database\Query\InsertQuery;
+use Cake\Database\Query\SelectQuery;
+use Cake\Database\Query\UpdateQuery;
 use Cake\Database\Retry\ReconnectStrategy;
 use Cake\Database\Schema\CachedCollection;
 use Cake\Database\Schema\Collection as SchemaCollection;
@@ -37,6 +41,7 @@
 use Psr\SimpleCache\CacheInterface;
 use RuntimeException;
 use Throwable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Represents a connection with a database server.
@@ -53,12 +58,14 @@ class Connection implements ConnectionInterface
     protected $_config;
 
     /**
-     * Driver object, responsible for creating the real connection
-     * and provide specific SQL dialect.
-     *
      * @var \Cake\Database\DriverInterface
      */
-    protected $_driver;
+    protected DriverInterface $readDriver;
+
+    /**
+     * @var \Cake\Database\DriverInterface
+     */
+    protected DriverInterface $writeDriver;
 
     /**
      * Contains how many nested transactions have been started.
@@ -135,19 +142,61 @@ class Connection implements ConnectionInterface
     public function __construct(array $config)
     {
         $this->_config = $config;
+        [self::ROLE_READ => $this->readDriver, self::ROLE_WRITE => $this->writeDriver] = $this->createDrivers($config);
+
+        if (!empty($config['log'])) {
+            $this->enableQueryLogging((bool)$config['log']);
+        }
+    }
 
-        $driverConfig = array_diff_key($config, array_flip([
+    /**
+     * Creates read and write drivers.
+     *
+     * @param array $config Connection config
+     * @return array
+     * @psalm-return array{read: \Cake\Database\DriverInterface, write: \Cake\Database\DriverInterface}
+     */
+    protected function createDrivers(array $config): array
+    {
+        $driver = $config['driver'] ?? '';
+        if (!is_string($driver)) {
+            /** @var \Cake\Database\DriverInterface $driver */
+            if (!$driver->enabled()) {
+                throw new MissingExtensionException(['driver' => get_class($driver), 'name' => $this->configName()]);
+            }
+
+            // Legacy support for setting instance instead of driver class
+            return [self::ROLE_READ => $driver, self::ROLE_WRITE => $driver];
+        }
+
+        /** @var class-string<\Cake\Database\DriverInterface>|null $driverClass */
+        $driverClass = App::className($driver, 'Database/Driver');
+        if ($driverClass === null) {
+            throw new MissingDriverException(['driver' => $driver, 'connection' => $this->configName()]);
+        }
+
+        $sharedConfig = array_diff_key($config, array_flip([
             'name',
             'driver',
             'log',
             'cacheMetaData',
             'cacheKeyPrefix',
         ]));
-        $this->_driver = $this->createDriver($config['driver'] ?? '', $driverConfig);
 
-        if (!empty($config['log'])) {
-            $this->enableQueryLogging((bool)$config['log']);
+        $writeConfig = $config['write'] ?? [] + $sharedConfig;
+        $readConfig = $config['read'] ?? [] + $sharedConfig;
+        if ($readConfig == $writeConfig) {
+            $readDriver = $writeDriver = new $driverClass(['_role' => self::ROLE_WRITE] + $writeConfig);
+        } else {
+            $readDriver = new $driverClass(['_role' => self::ROLE_READ] + $readConfig);
+            $writeDriver = new $driverClass(['_role' => self::ROLE_WRITE] + $writeConfig);
         }
+
+        if (!$writeDriver->enabled()) {
+            throw new MissingExtensionException(['driver' => get_class($writeDriver), 'name' => $this->configName()]);
+        }
+
+        return [self::ROLE_READ => $readDriver, self::ROLE_WRITE => $writeDriver];
     }
 
     /**
@@ -178,6 +227,16 @@ public function configName(): string
         return $this->_config['name'] ?? '';
     }
 
+    /**
+     * Returns the connection role: read or write.
+     *
+     * @return string
+     */
+    public function role(): string
+    {
+        return preg_match('/:read$/', $this->configName()) === 1 ? static::ROLE_READ : static::ROLE_WRITE;
+    }
+
     /**
      * Sets the driver instance. If a string is passed it will be treated
      * as a class name and will be instantiated.
@@ -193,7 +252,8 @@ public function setDriver($driver, $config = [])
     {
         deprecationWarning('Setting the driver is deprecated. Use the connection config instead.');
 
-        $this->_driver = $this->createDriver($driver, $config);
+        $driver = $this->createDriver($driver, $config);
+        $this->readDriver = $this->writeDriver = $driver;
 
         return $this;
     }
@@ -216,7 +276,7 @@ protected function createDriver($name, array $config): DriverInterface
             if ($className === null) {
                 throw new MissingDriverException(['driver' => $driver, 'connection' => $this->configName()]);
             }
-            $driver = new $className($config);
+            $driver = new $className(['_role' => self::ROLE_WRITE] + $config);
         }
 
         if (!$driver->enabled()) {
@@ -240,11 +300,14 @@ public function getDisconnectRetry(): CommandRetry
     /**
      * Gets the driver instance.
      *
+     * @param string $role Connection role ('read' or 'write')
      * @return \Cake\Database\DriverInterface
      */
-    public function getDriver(): DriverInterface
+    public function getDriver(string $role = self::ROLE_WRITE): DriverInterface
     {
-        return $this->_driver;
+        assert($role === self::ROLE_READ || $role === self::ROLE_WRITE);
+
+        return $role === self::ROLE_READ ? $this->readDriver : $this->writeDriver;
     }
 
     /**
@@ -252,43 +315,62 @@ public function getDriver(): DriverInterface
      *
      * @throws \Cake\Database\Exception\MissingConnectionException If database connection could not be established.
      * @return bool true, if the connection was already established or the attempt was successful.
+     * @deprecated 4.5.0 Use getDriver()->connect() instead.
      */
     public function connect(): bool
     {
-        try {
-            return $this->_driver->connect();
-        } catch (MissingConnectionException $e) {
-            throw $e;
-        } catch (Throwable $e) {
-            throw new MissingConnectionException(
-                [
-                    'driver' => App::shortName(get_class($this->_driver), 'Database/Driver'),
-                    'reason' => $e->getMessage(),
-                ],
-                null,
-                $e
-            );
+        deprecationWarning(
+            'If you cannot use automatic connection management, use $connection->getDriver()->connect() instead.'
+        );
+
+        $connected = true;
+        foreach ([self::ROLE_READ, self::ROLE_WRITE] as $role) {
+            try {
+                $connected = $connected && $this->getDriver($role)->connect();
+            } catch (MissingConnectionException $e) {
+                throw $e;
+            } catch (Throwable $e) {
+                throw new MissingConnectionException(
+                    [
+                        'driver' => App::shortName(get_class($this->getDriver($role)), 'Database/Driver'),
+                        'reason' => $e->getMessage(),
+                    ],
+                    null,
+                    $e
+                );
+            }
         }
+
+        return $connected;
     }
 
     /**
      * Disconnects from database server.
      *
      * @return void
+     * @deprecated 4.5.0 Use getDriver()->disconnect() instead.
      */
     public function disconnect(): void
     {
-        $this->_driver->disconnect();
+        deprecationWarning(
+            'If you cannot use automatic connection management, use $connection->getDriver()->disconnect() instead.'
+        );
+
+        $this->getDriver(self::ROLE_READ)->disconnect();
+        $this->getDriver(self::ROLE_WRITE)->disconnect();
     }
 
     /**
      * Returns whether connection to database server was already established.
      *
      * @return bool
+     * @deprecated 4.5.0 Use getDriver()->isConnected() instead.
      */
     public function isConnected(): bool
     {
-        return $this->_driver->isConnected();
+        deprecationWarning('Use $connection->getDriver()->isConnected() instead.');
+
+        return $this->getDriver(self::ROLE_READ)->isConnected() && $this->getDriver(self::ROLE_WRITE)->isConnected();
     }
 
     /**
@@ -296,11 +378,14 @@ public function isConnected(): bool
      *
      * @param \Cake\Database\Query|string $query The SQL to convert into a prepared statement.
      * @return \Cake\Database\StatementInterface
+     * @deprecated 4.5.0 Use getDriver()->prepare() instead.
      */
     public function prepare($query): StatementInterface
     {
-        return $this->getDisconnectRetry()->run(function () use ($query) {
-            $statement = $this->_driver->prepare($query);
+        $role = $query instanceof Query ? $query->getConnectionRole() : self::ROLE_WRITE;
+
+        return $this->getDisconnectRetry()->run(function () use ($query, $role) {
+            $statement = $this->getDriver($role)->prepare($query);
 
             if ($this->_logQueries) {
                 $statement = $this->_newLogger($statement);
@@ -339,10 +424,13 @@ public function execute(string $sql, array $params = [], array $types = []): Sta
      * @param \Cake\Database\Query $query The query to be compiled
      * @param \Cake\Database\ValueBinder $binder Value binder
      * @return string
+     * @deprecated 4.5.0 Use getDriver()->compileQuery() instead.
      */
     public function compileQuery(Query $query, ValueBinder $binder): string
     {
-        return $this->getDriver()->compileQuery($query, $binder)[1];
+        deprecationWarning('Use getDriver()->compileQuery() instead.');
+
+        return $this->getDriver($query->getConnectionRole())->compileQuery($query, $binder)[1];
     }
 
     /**
@@ -363,14 +451,42 @@ public function run(Query $query): StatementInterface
         });
     }
 
+    /**
+     * Create a new SelectQuery instance for this connection.
+     *
+     * @param \Cake\Database\ExpressionInterface|callable|array|string $fields fields to be added to the list.
+     * @param array|string $table The table or list of tables to query.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\SelectQuery
+     */
+    public function selectQuery(
+        $fields = [],
+        $table = [],
+        array $types = []
+    ): SelectQuery {
+        $query = new SelectQuery($this);
+        if ($table) {
+            $query->from($table);
+        }
+        if ($fields) {
+            $query->select($fields, false);
+        }
+        $query->setDefaultTypes($types);
+
+        return $query;
+    }
+
     /**
      * Executes a SQL statement and returns the Statement object as result.
      *
      * @param string $sql The SQL query to execute.
      * @return \Cake\Database\StatementInterface
+     * @deprecated 4.5.0 Use either `selectQuery`, `insertQuery`, `deleteQuery`, `updateQuery` instead.
      */
     public function query(string $sql): StatementInterface
     {
+        deprecationWarning('Use either `selectQuery`, `insertQuery`, `deleteQuery`, `updateQuery` instead.');
+
         return $this->getDisconnectRetry()->run(function () use ($sql) {
             $statement = $this->prepare($sql);
             $statement->execute();
@@ -383,9 +499,17 @@ public function query(string $sql): StatementInterface
      * Create a new Query instance for this connection.
      *
      * @return \Cake\Database\Query
+     * @deprecated 4.5.0 Use `insertQuery()`, `deleteQuery()`, `selectQuery()` or `updateQuery()` instead.
      */
     public function newQuery(): Query
     {
+        deprecationWarning(
+            'As of 4.5.0, using newQuery() is deprecated. Instead, use `insertQuery()`, ' .
+            '`deleteQuery()`, `selectQuery()` or `updateQuery()`. The query objects ' .
+            'returned by these methods will emit deprecations that will become fatal errors in 5.0.' .
+            'See https://book.cakephp.org/4/en/appendices/4-5-migration-guide.html for more information.'
+        );
+
         return new Query($this);
     }
 
@@ -435,13 +559,31 @@ public function getSchemaCollection(): SchemaCollectionInterface
     public function insert(string $table, array $values, array $types = []): StatementInterface
     {
         return $this->getDisconnectRetry()->run(function () use ($table, $values, $types) {
+            return $this->insertQuery($table, $values, $types)->execute();
+        });
+    }
+
+    /**
+     * Create a new InsertQuery instance for this connection.
+     *
+     * @param string|null $table The table to insert rows into.
+     * @param array $values Associative array of column => value to be inserted.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\InsertQuery
+     */
+    public function insertQuery(?string $table = null, array $values = [], array $types = []): InsertQuery
+    {
+        $query = new InsertQuery($this);
+        if ($table) {
+            $query->into($table);
+        }
+        if ($values) {
             $columns = array_keys($values);
+            $query->insert($columns, $types)
+                ->values($values);
+        }
 
-            return $this->newQuery()->insert($columns, $types)
-                ->into($table)
-                ->values($values)
-                ->execute();
-        });
+        return $query;
     }
 
     /**
@@ -456,13 +598,39 @@ public function insert(string $table, array $values, array $types = []): Stateme
     public function update(string $table, array $values, array $conditions = [], array $types = []): StatementInterface
     {
         return $this->getDisconnectRetry()->run(function () use ($table, $values, $conditions, $types) {
-            return $this->newQuery()->update($table)
-                ->set($values, $types)
-                ->where($conditions, $types)
-                ->execute();
+            return $this->updateQuery($table, $values, $conditions, $types)->execute();
         });
     }
 
+    /**
+     * Create a new UpdateQuery instance for this connection.
+     *
+     * @param \Cake\Database\ExpressionInterface|string|null $table The table to update rows of.
+     * @param array $values Values to be updated.
+     * @param array $conditions Conditions to be set for the update statement.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\UpdateQuery
+     */
+    public function updateQuery(
+        $table = null,
+        array $values = [],
+        array $conditions = [],
+        array $types = []
+    ): UpdateQuery {
+        $query = new UpdateQuery($this);
+        if ($table) {
+            $query->update($table);
+        }
+        if ($values) {
+            $query->set($values, $types);
+        }
+        if ($conditions) {
+            $query->where($conditions, $types);
+        }
+
+        return $query;
+    }
+
     /**
      * Executes a DELETE statement on the specified table.
      *
@@ -474,12 +642,31 @@ public function update(string $table, array $values, array $conditions = [], arr
     public function delete(string $table, array $conditions = [], array $types = []): StatementInterface
     {
         return $this->getDisconnectRetry()->run(function () use ($table, $conditions, $types) {
-            return $this->newQuery()->delete($table)
-                ->where($conditions, $types)
-                ->execute();
+            return $this->deleteQuery($table, $conditions, $types)->execute();
         });
     }
 
+    /**
+     * Create a new DeleteQuery instance for this connection.
+     *
+     * @param string|null $table The table to delete rows from.
+     * @param array $conditions Conditions to be set for the delete statement.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\DeleteQuery
+     */
+    public function deleteQuery(?string $table = null, array $conditions = [], array $types = []): DeleteQuery
+    {
+        $query = new DeleteQuery($this);
+        if ($table) {
+            $query->from($table);
+        }
+        if ($conditions) {
+            $query->where($conditions, $types);
+        }
+
+        return $query;
+    }
+
     /**
      * Starts a new transaction.
      *
@@ -493,7 +680,7 @@ public function begin(): void
             }
 
             $this->getDisconnectRetry()->run(function (): void {
-                $this->_driver->beginTransaction();
+                $this->getDriver()->beginTransaction();
             });
 
             $this->_transactionLevel = 0;
@@ -534,7 +721,7 @@ public function commit(): bool
                 $this->log('COMMIT');
             }
 
-            return $this->_driver->commitTransaction();
+            return $this->getDriver()->commitTransaction();
         }
         if ($this->isSavePointsEnabled()) {
             $this->releaseSavePoint((string)$this->_transactionLevel);
@@ -569,7 +756,7 @@ public function rollback(?bool $toBeginning = null): bool
             if ($this->_logQueries) {
                 $this->log('ROLLBACK');
             }
-            $this->_driver->rollbackTransaction();
+            $this->getDriver()->rollbackTransaction();
 
             return true;
         }
@@ -598,7 +785,7 @@ public function enableSavePoints(bool $enable = true)
         if ($enable === false) {
             $this->_useSavePoints = false;
         } else {
-            $this->_useSavePoints = $this->_driver->supports(DriverInterface::FEATURE_SAVEPOINT);
+            $this->_useSavePoints = $this->getDriver()->supports(DriverInterface::FEATURE_SAVEPOINT);
         }
 
         return $this;
@@ -634,7 +821,7 @@ public function isSavePointsEnabled(): bool
      */
     public function createSavePoint($name): void
     {
-        $this->execute($this->_driver->savePointSQL($name))->closeCursor();
+        $this->execute($this->getDriver()->savePointSQL($name))->closeCursor();
     }
 
     /**
@@ -645,7 +832,7 @@ public function createSavePoint($name): void
      */
     public function releaseSavePoint($name): void
     {
-        $sql = $this->_driver->releaseSavePointSQL($name);
+        $sql = $this->getDriver()->releaseSavePointSQL($name);
         if ($sql) {
             $this->execute($sql)->closeCursor();
         }
@@ -659,7 +846,7 @@ public function releaseSavePoint($name): void
      */
     public function rollbackSavepoint($name): void
     {
-        $this->execute($this->_driver->rollbackSavePointSQL($name))->closeCursor();
+        $this->execute($this->getDriver()->rollbackSavePointSQL($name))->closeCursor();
     }
 
     /**
@@ -670,7 +857,7 @@ public function rollbackSavepoint($name): void
     public function disableForeignKeys(): void
     {
         $this->getDisconnectRetry()->run(function (): void {
-            $this->execute($this->_driver->disableForeignKeySQL())->closeCursor();
+            $this->execute($this->getDriver()->disableForeignKeySQL())->closeCursor();
         });
     }
 
@@ -682,7 +869,7 @@ public function disableForeignKeys(): void
     public function enableForeignKeys(): void
     {
         $this->getDisconnectRetry()->run(function (): void {
-            $this->execute($this->_driver->enableForeignKeySQL())->closeCursor();
+            $this->execute($this->getDriver()->enableForeignKeySQL())->closeCursor();
         });
     }
 
@@ -695,7 +882,7 @@ public function enableForeignKeys(): void
      */
     public function supportsDynamicConstraints(): bool
     {
-        return $this->_driver->supportsDynamicConstraints();
+        return $this->getDriver()->supportsDynamicConstraints();
     }
 
     /**
@@ -774,12 +961,14 @@ public function inTransaction(): bool
      * @param mixed $value The value to quote.
      * @param \Cake\Database\TypeInterface|string|int $type Type to be used for determining kind of quoting to perform
      * @return string Quoted value
+     * @deprecated 4.5.0 Use getDriver()->quote() instead.
      */
     public function quote($value, $type = 'string'): string
     {
+        deprecationWarning('Use getDriver()->quote() instead.');
         [$value, $type] = $this->cast($value, $type);
 
-        return $this->_driver->quote($value, $type);
+        return $this->getDriver()->quote($value, $type);
     }
 
     /**
@@ -788,10 +977,13 @@ public function quote($value, $type = 'string'): string
      * This is not required to use `quoteIdentifier()`.
      *
      * @return bool
+     * @deprecated 4.5.0 Use getDriver()->supportsQuoting() instead.
      */
     public function supportsQuoting(): bool
     {
-        return $this->_driver->supports(DriverInterface::FEATURE_QUOTE);
+        deprecationWarning('Use getDriver()->supportsQuoting() instead.');
+
+        return $this->getDriver()->supports(DriverInterface::FEATURE_QUOTE);
     }
 
     /**
@@ -802,10 +994,13 @@ public function supportsQuoting(): bool
      *
      * @param string $identifier The identifier to quote.
      * @return string
+     * @deprecated 4.5.0 Use getDriver()->quoteIdentifier() instead.
      */
     public function quoteIdentifier(string $identifier): string
     {
-        return $this->_driver->quoteIdentifier($identifier);
+        deprecationWarning('Use getDriver()->quoteIdentifier() instead.');
+
+        return $this->getDriver()->quoteIdentifier($identifier);
     }
 
     /**
@@ -865,6 +1060,7 @@ public function getCacher(): CacheInterface
      *
      * @param bool $enable Enable/disable query logging
      * @return $this
+     * @deprecated 4.5.0 Connection logging is moving to the driver in 5.x
      */
     public function enableQueryLogging(bool $enable = true)
     {
@@ -877,6 +1073,7 @@ public function enableQueryLogging(bool $enable = true)
      * Disable query logging
      *
      * @return $this
+     * @deprecated 4.5.0 Connection logging is moving to the driver in 5.x
      */
     public function disableQueryLogging()
     {
@@ -889,6 +1086,7 @@ public function disableQueryLogging()
      * Check if query logging is enabled.
      *
      * @return bool
+     * @deprecated 4.5.0 Connection logging is moving to the driver in 5.x
      */
     public function isQueryLoggingEnabled(): bool
     {
@@ -952,7 +1150,7 @@ public function log(string $sql): void
      */
     protected function _newLogger(StatementInterface $statement): LoggingStatement
     {
-        $log = new LoggingStatement($statement, $this->_driver);
+        $log = new LoggingStatement($statement, $this->getDriver());
         $log->setLogger($this->getLogger());
 
         return $log;
@@ -976,9 +1174,19 @@ public function __debugInfo(): array
         $replace = array_intersect_key($secrets, $this->_config);
         $config = $replace + $this->_config;
 
+        if (isset($config['read'])) {
+            /** @psalm-suppress PossiblyInvalidArgument */
+            $config['read'] = array_intersect_key($secrets, $config['read']) + $config['read'];
+        }
+        if (isset($config['write'])) {
+            /** @psalm-suppress PossiblyInvalidArgument */
+            $config['write'] = array_intersect_key($secrets, $config['write']) + $config['write'];
+        }
+
         return [
             'config' => $config,
-            'driver' => $this->_driver,
+            'readDriver' => $this->readDriver,
+            'writeDriver' => $this->writeDriver,
             'transactionLevel' => $this->_transactionLevel,
             'transactionStarted' => $this->_transactionStarted,
             'useSavePoints' => $this->_useSavePoints,
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver.php b/app/vendor/cakephp/cakephp/src/Database/Driver.php
index 249868c47..5d43f1acc 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver.php
@@ -27,6 +27,7 @@
 use InvalidArgumentException;
 use PDO;
 use PDOException;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Represents a database driver containing all specificities for
@@ -108,6 +109,16 @@ public function __construct(array $config = [])
         }
     }
 
+    /**
+     * Get the configuration data used to create the driver.
+     *
+     * @return array
+     */
+    public function config(): array
+    {
+        return $this->_config;
+    }
+
     /**
      * Establishes a connection to the database server
      *
@@ -513,6 +524,16 @@ public function getConnectRetries(): int
         return $this->connectRetries;
     }
 
+    /**
+     * Returns the connection role this driver performs.
+     *
+     * @return string
+     */
+    public function getRole(): string
+    {
+        return $this->_config['_role'] ?? Connection::ROLE_WRITE;
+    }
+
     /**
      * Destructor
      */
@@ -532,6 +553,7 @@ public function __debugInfo(): array
     {
         return [
             'connected' => $this->_connection !== null,
+            'role' => $this->getRole(),
         ];
     }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php b/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php
index 68f46ff74..b7d30b69f 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php
@@ -23,6 +23,7 @@
 use Cake\Database\Statement\MysqlStatement;
 use Cake\Database\StatementInterface;
 use PDO;
+use function Cake\Core\deprecationWarning;
 
 /**
  * MySQL Driver
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php b/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php
index 7bcabda6b..94a5e88b9 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php
@@ -306,3 +306,10 @@ public function rollbackSavePointSQL($name): string
         return 'ROLLBACK TO SAVEPOINT LEVEL' . $name;
     }
 }
+
+// phpcs:disable
+class_alias(
+    'Cake\Database\Driver\SqlDialectTrait',
+    'Cake\Database\SqlDialectTrait'
+);
+// phpcs:enable
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php
index 6ca955856..65c3e7a1d 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php
@@ -30,6 +30,7 @@
 use InvalidArgumentException;
 use PDO;
 use RuntimeException;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Class Sqlite
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php b/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php
index e94b268b5..e21a79d08 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php
@@ -90,8 +90,7 @@ protected function _transformTupleComparison(TupleComparison $expression, Query
         }
 
         $surrogate = $query->getConnection()
-            ->newQuery()
-            ->select($true);
+            ->selectQuery($true);
 
         if (!is_array(current($value))) {
             $value = [$value];
diff --git a/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php b/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php
index e2ccc4d31..914d6b755 100644
--- a/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php
@@ -27,6 +27,8 @@
  * @method int getConnectRetries() Returns the number of connection retry attempts made.
  * @method bool supports(string $feature) Checks whether a feature is supported by the driver.
  * @method bool inTransaction() Returns whether a transaction is active.
+ * @method array config() Get the configuration data used to create the driver.
+ * @method string getRole() Returns the connection role this driver prforms.
  */
 interface DriverInterface
 {
diff --git a/app/vendor/cakephp/cakephp/src/Database/Exception.php b/app/vendor/cakephp/cakephp/src/Database/Exception.php
index d47914df0..b8f495836 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Exception.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Exception.php
@@ -1,16 +1,10 @@
 _conditions[] = $conditions;
-
-            return $this;
-        }
-
-        if ($conditions instanceof ExpressionInterface) {
+        if (is_string($conditions) || $conditions instanceof ExpressionInterface) {
             $this->_conditions[] = $conditions;
 
             return $this;
diff --git a/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php b/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php
index bf51eaf19..bbc415414 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php
@@ -24,6 +24,7 @@
 use Closure;
 use InvalidArgumentException;
 use LogicException;
+use function Cake\Core\getTypeName;
 
 /**
  * Represents a SQL when/then clause with a fluid API
diff --git a/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php b/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php
index 1251fcad4..9e50ad63c 100644
--- a/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php
+++ b/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php
@@ -19,6 +19,7 @@
 use Cake\Database\Expression\AggregateExpression;
 use Cake\Database\Expression\FunctionExpression;
 use InvalidArgumentException;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Contains methods related to generating FunctionExpression objects
diff --git a/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php b/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php
index 6560a367f..f029bc935 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php
@@ -130,6 +130,7 @@ public function getContext(): array
         return [
             'numRows' => $this->numRows,
             'took' => $this->took,
+            'role' => $this->driver ? $this->driver->getRole() : '',
         ];
     }
 
diff --git a/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php b/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php
index ada3d381d..e83f6f60e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php
@@ -21,6 +21,7 @@
 use Cake\Database\Statement\StatementDecorator;
 use Exception;
 use Psr\Log\LoggerInterface;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Statement decorator used to
diff --git a/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php b/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php
index a7f27b489..e2faadce2 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php
@@ -50,7 +50,7 @@ public function log($level, $message, array $context = [])
 
         if ($context['query'] instanceof LoggedQuery) {
             $context = $context['query']->getContext() + $context;
-            $message = 'connection={connection} duration={took} rows={numRows} ' . $message;
+            $message = 'connection={connection} role={role} duration={took} rows={numRows} ' . $message;
         }
         Log::write('debug', (string)$message, $context);
     }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query.php b/app/vendor/cakephp/cakephp/src/Database/Query.php
index 503c3a443..594b8a70f 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Query.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Query.php
@@ -30,6 +30,7 @@
 use IteratorAggregate;
 use RuntimeException;
 use Throwable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * This class represents a Relational database SQL Query. A query can be of
@@ -63,6 +64,13 @@ class Query implements ExpressionInterface, IteratorAggregate
      */
     protected $_connection;
 
+    /**
+     * Connection role ('read' or 'write')
+     *
+     * @var string
+     */
+    protected $connectionRole = Connection::ROLE_WRITE;
+
     /**
      * Type of this query (select, insert, update, delete).
      *
@@ -178,6 +186,7 @@ class Query implements ExpressionInterface, IteratorAggregate
      * are enabled.
      *
      * @var bool
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     protected $_useBufferedResults = true;
 
@@ -230,6 +239,16 @@ public function getConnection(): Connection
         return $this->_connection;
     }
 
+    /**
+     * Returns the connection role ('read' or 'write')
+     *
+     * @return string
+     */
+    public function getConnectionRole(): string
+    {
+        return $this->connectionRole;
+    }
+
     /**
      * Compiles the SQL representation of this query and executes it using the
      * configured connection object. Returns the resulting statement object.
@@ -311,8 +330,9 @@ public function sql(?ValueBinder $binder = null): string
             $binder = $this->getValueBinder();
             $binder->resetCount();
         }
+        $connection = $this->getConnection();
 
-        return $this->getConnection()->compileQuery($this, $binder);
+        return $connection->getDriver($this->getConnectionRole())->compileQuery($this, $binder)[1];
     }
 
     /**
@@ -428,7 +448,7 @@ public function with($cte, bool $overwrite = false)
         }
 
         if ($cte instanceof Closure) {
-            $query = $this->getConnection()->newQuery();
+            $query = $this->getConnection()->selectQuery();
             $cte = $cte(new CommonTableExpression(), $query);
             if (!($cte instanceof CommonTableExpression)) {
                 throw new RuntimeException(
@@ -864,7 +884,6 @@ public function innerJoin($table, $conditions = [], $types = [])
      * to use for joining.
      * @param string $type the join type to use
      * @return array
-     * @psalm-suppress InvalidReturnType
      */
     protected function _makeJoin($table, $conditions, $type): array
     {
@@ -877,7 +896,6 @@ protected function _makeJoin($table, $conditions, $type): array
 
         /**
          * @psalm-suppress InvalidArrayOffset
-         * @psalm-suppress InvalidReturnStatement
          */
         return [
             $alias => [
@@ -2197,9 +2215,15 @@ public function setValueBinder(?ValueBinder $binder)
      *
      * @param bool $enable Whether to enable buffering
      * @return $this
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     public function enableBufferedResults(bool $enable = true)
     {
+        if (!$enable) {
+            deprecationWarning(
+                '4.5.0 enableBufferedResults() is deprecated. Results will always be buffered in 5.0.'
+            );
+        }
         $this->_dirty();
         $this->_useBufferedResults = $enable;
 
@@ -2213,6 +2237,7 @@ public function enableBufferedResults(bool $enable = true)
      * remembered for future iterations.
      *
      * @return $this
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     public function disableBufferedResults()
     {
@@ -2233,6 +2258,7 @@ public function disableBufferedResults()
      * remembered for future iterations.
      *
      * @return bool
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     public function isBufferedResultsEnabled(): bool
     {
@@ -2327,7 +2353,7 @@ public function isResultsCastingEnabled(): bool
     protected function _decorateStatement(StatementInterface $statement)
     {
         $typeMap = $this->getSelectTypeMap();
-        $driver = $this->getConnection()->getDriver();
+        $driver = $this->getConnection()->getDriver($this->connectionRole);
 
         if ($this->typeCastEnabled && $typeMap->toArray()) {
             $statement = new CallbackStatement($statement, $driver, new FieldTypeConverter($typeMap, $driver));
@@ -2418,7 +2444,6 @@ public function __clone()
                             }
                         }
                     } elseif ($piece instanceof ExpressionInterface) {
-                        /** @psalm-suppress PossiblyUndefinedMethod */
                         $this->_parts[$name][$i] = clone $piece;
                     }
                 }
@@ -2473,4 +2498,19 @@ function ($errno, $errstr) {
             'executed' => $this->_iterator ? true : false,
         ];
     }
+
+    /**
+     * Helper for Query deprecation methods.
+     *
+     * @param string $method The method that is invalid.
+     * @param string $message An additional message.
+     * @return void
+     * @internal
+     */
+    protected function _deprecatedMethod($method, $message = '')
+    {
+        $class = static::class;
+        $text = "As of 4.5.0 calling {$method}() on {$class} is deprecated. " . $message;
+        deprecationWarning($text);
+    }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/DeleteQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/DeleteQuery.php
new file mode 100644
index 000000000..5c11ae9d7
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/DeleteQuery.php
@@ -0,0 +1,222 @@
+_deprecatedMethod('select()', 'Create your query with selectQuery() instead.');
+
+        return parent::select($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function distinct($on = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('distint()');
+
+        return parent::distinct($on, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function modifier($modifiers, $overwrite = false)
+    {
+        $this->_deprecatedMethod('modifier()');
+
+        return parent::modifier($modifiers, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function order($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('order()');
+
+        return parent::order($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderAsc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderAsc()');
+
+        return parent::orderAsc($field, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderDesc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderDesc()');
+
+        return parent::orderDesc($field, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function group($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('group()');
+
+        return parent::group($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function having($conditions = null, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('having()');
+
+        return parent::having($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andHaving($conditions, $types = [])
+    {
+        $this->_deprecatedMethod('andHaving()');
+
+        return parent::andHaving($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function page(int $num, ?int $limit = null)
+    {
+        $this->_deprecatedMethod('page()');
+
+        return parent::page($num, $limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function limit($limit)
+    {
+        $this->_deprecatedMethod('limit()');
+
+        return parent::limit($limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offset($offset)
+    {
+        $this->_deprecatedMethod('offset()');
+
+        return parent::offset($offset);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function union($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::union($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function unionAll($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('unionAll()');
+
+        return parent::unionAll($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function insert(array $columns, array $types = [])
+    {
+        $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.');
+
+        return parent::insert($columns, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function into(string $table)
+    {
+        $this->_deprecatedMethod('into()');
+
+        return parent::into($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function values($data)
+    {
+        $this->_deprecatedMethod('values()');
+
+        return parent::values($data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function update($table)
+    {
+        $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.');
+
+        return parent::update($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function set($key, $value = null, $types = [])
+    {
+        $this->_deprecatedMethod('set()');
+
+        return parent::set($key, $value, $types);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/InsertQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/InsertQuery.php
new file mode 100644
index 000000000..7d326239b
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/InsertQuery.php
@@ -0,0 +1,322 @@
+_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.');
+
+        return parent::delete($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function select($fields = [], bool $overwrite = false)
+    {
+        $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.');
+
+        return parent::select($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function distinct($on = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('distinct()');
+
+        return parent::distinct($on, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function modifier($modifiers, $overwrite = false)
+    {
+        $this->_deprecatedMethod('modifier()');
+
+        return parent::modifier($modifiers, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function join($tables, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('join()');
+
+        return parent::join($tables, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function removeJoin(string $name)
+    {
+        $this->_deprecatedMethod('removeJoin()');
+
+        return parent::removeJoin($name);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function leftJoin($table, $conditions = [], $types = [])
+    {
+        $this->_deprecatedMethod('leftJoin()');
+
+        return parent::leftJoin($table, $conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function rightJoin($table, $conditions = [], $types = [])
+    {
+        $this->_deprecatedMethod('rightJoin()');
+
+        return parent::rightJoin($table, $conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function innerJoin($table, $conditions = [], $types = [])
+    {
+        $this->_deprecatedMethod('innerJoin()');
+
+        return parent::innerJoin($table, $conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function group($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('group()');
+
+        return parent::group($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function having($conditions = null, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('having()');
+
+        return parent::having($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andHaving($conditions, $types = [])
+    {
+        $this->_deprecatedMethod('andHaving()');
+
+        return parent::andHaving($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function page(int $num, ?int $limit = null)
+    {
+        $this->_deprecatedMethod('page()');
+
+        return parent::page($num, $limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offset($offset)
+    {
+        $this->_deprecatedMethod('offset()');
+
+        return parent::offset($offset);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function union($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::union($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function unionAll($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::unionAll($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function from($tables = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('from()', 'Use into() instead.');
+
+        return parent::from($tables, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function update($table)
+    {
+        $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.');
+
+        return parent::update($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function set($key, $value = null, $types = [])
+    {
+        $this->_deprecatedMethod('set()');
+
+        return parent::set($key, $value, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function where($conditions = null, array $types = [], bool $overwrite = false)
+    {
+        $this->_deprecatedMethod('where()');
+
+        return parent::where($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNotNull($fields)
+    {
+        $this->_deprecatedMethod('whereNotNull()');
+
+        return parent::whereNotNull($fields);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNull($fields)
+    {
+        $this->_deprecatedMethod('whereNull()');
+
+        return parent::whereNull($fields);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereInList(string $field, array $values, array $options = [])
+    {
+        $this->_deprecatedMethod('whereInList()');
+
+        return parent::whereInList($field, $values, $options);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNotInList(string $field, array $values, array $options = [])
+    {
+        $this->_deprecatedMethod('whereNotInList()');
+
+        return parent::whereNotInList($field, $values, $options);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNotInListOrNull(string $field, array $values, array $options = [])
+    {
+        $this->_deprecatedMethod('whereNotInListOrNull()');
+
+        return parent::whereNotInListOrNull($field, $values, $options);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andWhere($conditions, array $types = [])
+    {
+        $this->_deprecatedMethod('andWhere()');
+
+        return parent::andWhere($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function order($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('order()');
+
+        return parent::order($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderAsc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderAsc()');
+
+        return parent::orderAsc($field, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderDesc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderDesc()');
+
+        return parent::orderDesc($field, $overwrite);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/SelectQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/SelectQuery.php
new file mode 100644
index 000000000..7d2986aba
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/SelectQuery.php
@@ -0,0 +1,127 @@
+_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.');
+
+        return parent::delete($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function insert(array $columns, array $types = [])
+    {
+        $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.');
+
+        return parent::insert($columns, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function into(string $table)
+    {
+        $this->_deprecatedMethod('into()', 'Use from() instead.');
+
+        return parent::into($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function values($data)
+    {
+        $this->_deprecatedMethod('values()');
+
+        return parent::values($data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function update($table)
+    {
+        $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.');
+
+        return parent::update($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function set($key, $value = null, $types = [])
+    {
+        $this->_deprecatedMethod('set()');
+
+        return parent::set($key, $value, $types);
+    }
+
+    /**
+     * Sets the connection role.
+     *
+     * @param string $role Connection role ('read' or 'write')
+     * @return $this
+     */
+    public function setConnectionRole(string $role)
+    {
+        assert($role === Connection::ROLE_READ || $role === Connection::ROLE_WRITE);
+        $this->connectionRole = $role;
+
+        return $this;
+    }
+
+    /**
+     * Sets the connection role to read.
+     *
+     * @return $this
+     */
+    public function useReadRole()
+    {
+        return $this->setConnectionRole(Connection::ROLE_READ);
+    }
+
+    /**
+     * Sets the connection role to write.
+     *
+     * @return $this
+     */
+    public function useWriteRole()
+    {
+        return $this->setConnectionRole(Connection::ROLE_WRITE);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/UpdateQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/UpdateQuery.php
new file mode 100644
index 000000000..0f84cce6c
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/UpdateQuery.php
@@ -0,0 +1,182 @@
+_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.');
+
+        return parent::delete($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function select($fields = [], bool $overwrite = false)
+    {
+        $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.');
+
+        return parent::select($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function distinct($on = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('distinct()');
+
+        return parent::distinct($on, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function modifier($modifiers, $overwrite = false)
+    {
+        $this->_deprecatedMethod('modifier()');
+
+        return parent::modifier($modifiers, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function group($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('group()');
+
+        return parent::group($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function having($conditions = null, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('having()');
+
+        return parent::having($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andHaving($conditions, $types = [])
+    {
+        $this->_deprecatedMethod('andHaving()');
+
+        return parent::andHaving($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function page(int $num, ?int $limit = null)
+    {
+        $this->_deprecatedMethod('page()');
+
+        return parent::page($num, $limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offset($offset)
+    {
+        $this->_deprecatedMethod('offset()');
+
+        return parent::offset($offset);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function union($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::union($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function unionAll($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::unionAll($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function insert(array $columns, array $types = [])
+    {
+        $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.');
+
+        return parent::insert($columns, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function into(string $table)
+    {
+        $this->_deprecatedMethod('into()', 'Use update() instead.');
+
+        return parent::into($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function values($data)
+    {
+        $this->_deprecatedMethod('values()');
+
+        return parent::values($data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function from($tables = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('from()', 'Use update() instead.');
+
+        return parent::from($tables, $overwrite);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php b/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php
index 236d5eb72..9ed44223e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php
+++ b/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php
@@ -201,7 +201,7 @@ protected function _buildSelectPart(array $parts, Query $query, ValueBinder $bin
         $distinct = $query->clause('distinct');
         $modifiers = $this->_buildModifierPart($query->clause('modifier'), $query, $binder);
 
-        $driver = $query->getConnection()->getDriver();
+        $driver = $query->getConnection()->getDriver($query->getConnectionRole());
         $quoteIdentifiers = $driver->isAutoQuotingEnabled() || $this->_quotedSelectAliases;
         $normalized = [];
         $parts = $this->_stringifyExpressions($parts, $binder);
diff --git a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php
index 7d76cc01e..25fb69f80 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php
@@ -104,12 +104,12 @@ protected function reconnect(): bool
 
         try {
             // Make sure we free any resources associated with the old connection
-            $this->connection->disconnect();
+            $this->connection->getDriver()->disconnect();
         } catch (Exception $e) {
         }
 
         try {
-            $this->connection->connect();
+            $this->connection->getDriver()->connect();
             if ($this->connection->isQueryLoggingEnabled()) {
                 $this->connection->log('[RECONNECT]');
             }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php b/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php
index 46513170d..8d32d3448 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php
@@ -1,5 +1,10 @@
 _dialect->listTablesWithoutViewsSql($this->_connection->config());
+        [$sql, $params] = $this->_dialect->listTablesWithoutViewsSql($this->_connection->getDriver()->config());
         $result = [];
         $statement = $this->_connection->execute($sql, $params);
         while ($row = $statement->fetch()) {
@@ -78,7 +78,7 @@ public function listTablesWithoutViews(): array
      */
     public function listTables(): array
     {
-        [$sql, $params] = $this->_dialect->listTablesSql($this->_connection->config());
+        [$sql, $params] = $this->_dialect->listTablesSql($this->_connection->getDriver()->config());
         $result = [];
         $statement = $this->_connection->execute($sql, $params);
         while ($row = $statement->fetch()) {
@@ -109,7 +109,7 @@ public function listTables(): array
      */
     public function describe(string $name, array $options = []): TableSchemaInterface
     {
-        $config = $this->_connection->config();
+        $config = $this->_connection->getDriver()->config();
         if (strpos($name, '.')) {
             [$config['schema'], $name] = explode('.', $name);
         }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php b/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php
index 237d6362b..30b20db6e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php
@@ -1,5 +1,10 @@
  TableSchema::TYPE_BOOLEAN, 'length' => null];
         }
 
-        if ($col === 'char' && $length === 36) {
+        if (($col === 'char' && $length === 36) || $col === 'uuid') {
             return ['type' => TableSchema::TYPE_UUID, 'length' => null];
         }
         if ($col === 'char') {
@@ -642,6 +642,8 @@ public function hasSequences(): bool
 }
 
 // phpcs:disable
-// Add backwards compatible alias.
-class_alias('Cake\Database\Schema\SqliteSchemaDialect', 'Cake\Database\Schema\SqliteSchema');
+class_alias(
+    'Cake\Database\Schema\SqliteSchemaDialect',
+    'Cake\Database\Schema\SqliteSchema'
+);
 // phpcs:enable
diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php b/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php
index dbe584efd..62e3f6981 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php
@@ -1,5 +1,10 @@
 _schema->describe($table, ['forceRefresh' => true]);
         }
 
@@ -86,7 +85,6 @@ public function clear(?string $name = null): array
         $cacher = $this->_schema->getCacher();
 
         foreach ($tables as $table) {
-            /** @psalm-suppress PossiblyNullArgument */
             $key = $this->_schema->cacheKey($table);
             $cacher->delete($key);
         }
diff --git a/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php b/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php
index 38ef7bc08..763f8fd70 100644
--- a/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php
@@ -1,5 +1,10 @@
 
  */
 class BufferedStatement implements Iterator, StatementInterface
 {
@@ -85,6 +87,16 @@ public function __construct(StatementInterface $statement, DriverInterface $driv
         $this->_driver = $driver;
     }
 
+    /**
+     * Returns the connection driver.
+     *
+     * @return \Cake\Database\DriverInterface
+     */
+    protected function getDriver(): DriverInterface
+    {
+        return $this->_driver;
+    }
+
     /**
      * Magic getter to return $queryString as read-only.
      *
diff --git a/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php b/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php
index 5e7309ad1..6cbc82720 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php
@@ -20,6 +20,7 @@
 use Cake\Database\DriverInterface;
 use PDO;
 use PDOStatement as Statement;
+use function Cake\Core\getTypeName;
 
 /**
  * Decorator for \PDOStatement class mainly used for converting human readable
@@ -55,7 +56,6 @@ public function __construct(Statement $statement, DriverInterface $driver)
     public function __get(string $property)
     {
         if ($property === 'queryString' && isset($this->_statement->queryString)) {
-            /** @psalm-suppress NoInterfaceProperties */
             return $this->_statement->queryString;
         }
 
diff --git a/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php b/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php
index efd3b6a2c..39f3be8c3 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php
@@ -45,7 +45,6 @@ public function bindValue($column, $value, $type = 'string'): void
             [$value, $type] = $this->cast($value, $type);
         }
         if ($type === PDO::PARAM_LOB) {
-            /** @psalm-suppress UndefinedConstant */
             $this->_statement->bindParam($column, $value, $type, 0, PDO::SQLSRV_ENCODING_BINARY);
         } else {
             $this->_statement->bindValue($column, $value, $type);
diff --git a/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php b/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php
index 4a1d33e95..2c2f46bfa 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php
@@ -32,6 +32,7 @@
  * PDOStatement.
  *
  * @property-read string $queryString
+ * @template-implements \IteratorAggregate
  */
 class StatementDecorator implements StatementInterface, Countable, IteratorAggregate
 {
@@ -72,6 +73,16 @@ public function __construct(StatementInterface $statement, DriverInterface $driv
         $this->_driver = $driver;
     }
 
+    /**
+     * Returns the connection driver.
+     *
+     * @return \Cake\Database\DriverInterface
+     */
+    protected function getDriver(): DriverInterface
+    {
+        return $this->_driver;
+    }
+
     /**
      * Magic getter to return $queryString as read-only.
      *
@@ -326,7 +337,6 @@ public function bind(array $params, array $types): void
                 /** @psalm-suppress InvalidOperand */
                 $index += $offset;
             }
-            /** @psalm-suppress InvalidScalarArgument */
             $this->bindValue($index, $value, $type);
         }
     }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type.php b/app/vendor/cakephp/cakephp/src/Database/Type.php
index 466b8d597..164419c87 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type.php
@@ -1,5 +1,9 @@
 setTimezone($this->defaultTimezone);
         }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php b/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php
index 19d5453fe..0cd63cd6c 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php
@@ -22,6 +22,8 @@
 use DateTime;
 use DateTimeImmutable;
 use DateTimeInterface;
+use Exception;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Class DateType
@@ -102,14 +104,61 @@ public function useMutable()
      */
     public function marshal($value): ?DateTimeInterface
     {
-        $date = parent::marshal($value);
-        /** @psalm-var \DateTime|\DateTimeImmutable|null $date */
-        if ($date && !$date instanceof I18nDateTimeInterface) {
-            // Clear time manually when I18n types aren't available and raw DateTime used
-            $date = $date->setTime(0, 0, 0);
+        if ($value instanceof DateTimeInterface) {
+            return new FrozenDate($value);
         }
 
-        return $date;
+        /** @var class-string<\Cake\Chronos\ChronosDate> $class */
+        $class = $this->_className;
+        try {
+            if ($value === '' || $value === null || is_bool($value)) {
+                return null;
+            }
+
+            if (is_int($value) || (is_string($value) && ctype_digit($value))) {
+                /** @var \Cake\I18n\FrozenDate|\DateTimeImmutable $dateTime */
+                $dateTime = new $class('@' . $value);
+
+                return $dateTime;
+            }
+
+            if (is_string($value)) {
+                if ($this->_useLocaleMarshal) {
+                    $dateTime = $this->_parseLocaleValue($value);
+                } else {
+                    $dateTime = $this->_parseValue($value);
+                }
+
+                return $dateTime;
+            }
+        } catch (Exception $e) {
+            return null;
+        }
+
+        if (is_array($value) && implode('', $value) === '') {
+            return null;
+        }
+        $format = '';
+        if (
+            isset($value['year'], $value['month'], $value['day']) &&
+            (
+                is_numeric($value['year']) &&
+                is_numeric($value['month']) &&
+                is_numeric($value['day'])
+            )
+        ) {
+            $format .= sprintf('%d-%02d-%02d', $value['year'], $value['month'], $value['day']);
+        }
+
+        if (empty($format)) {
+            // Invalid array format.
+            return null;
+        }
+
+        /** @var \Cake\I18n\FrozenDate|\DateTimeImmutable $dateTime */
+        $dateTime = new $class($format);
+
+        return $dateTime;
     }
 
     /**
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php b/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php
index cb332fd37..f06f6d795 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php
@@ -21,6 +21,7 @@
 use InvalidArgumentException;
 use PDO;
 use RuntimeException;
+use function Cake\Core\getTypeName;
 
 /**
  * Decimal type converter.
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php b/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php
index 4a84c59e3..973d7ca55 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php
@@ -19,6 +19,7 @@
 use Cake\Database\DriverInterface;
 use InvalidArgumentException;
 use PDO;
+use function Cake\Core\getTypeName;
 
 /**
  * Integer type converter.
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php b/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php
index 4dd38bc86..4c98e3369 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php
@@ -19,6 +19,7 @@
 use Cake\Database\DriverInterface;
 use InvalidArgumentException;
 use PDO;
+use function Cake\Core\getTypeName;
 
 /**
  * String type converter.
diff --git a/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php b/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php
index f92c85027..2f04b814e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php
@@ -36,8 +36,8 @@ public function cast($value, $type = 'string'): array
             $type = TypeFactory::build($type);
         }
         if ($type instanceof TypeInterface) {
-            $value = $type->toDatabase($value, $this->_driver);
-            $type = $type->toStatement($value, $this->_driver);
+            $value = $type->toDatabase($value, $this->getDriver());
+            $type = $type->toStatement($value, $this->getDriver());
         }
 
         return [$value, $type];
diff --git a/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php b/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php
index 2f5006697..617bad6d9 100644
--- a/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php
+++ b/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php
@@ -162,3 +162,10 @@ public static function clear(): void
         static::$_builtTypes = [];
     }
 }
+
+// phpcs:disable
+class_alias(
+    'Cake\Database\TypeFactory',
+    'Cake\Database\Type'
+);
+// phpcs:enable
diff --git a/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php b/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php
index 1a63a57d9..0e5dd3d08 100644
--- a/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php
+++ b/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php
@@ -148,4 +148,16 @@ public function attachTo(StatementInterface $statement): void
             $statement->bindValue($b['placeholder'], $b['value'], $b['type']);
         }
     }
+
+    /**
+     * Get verbose debugging data.
+     *
+     * @return array
+     */
+    public function __debugInfo(): array
+    {
+        return [
+            'bindings' => $this->bindings(),
+        ];
+    }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php
index 01a7d5330..7efef433d 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php
@@ -30,8 +30,6 @@
  *   already created tables. {@see \Cake\Database\Connnection::supportsDynamicConstraints()}
  * @method \Cake\Database\Schema\Collection getSchemaCollection() Gets a Schema\Collection object for this connection.
  *    {@see \Cake\Database\Connnection::getSchemaCollection()}
- * @method \Cake\Database\Query newQuery() Create a new Query instance for this connection.
- *    {@see \Cake\Database\Connnection::newQuery()}
  * @method \Cake\Database\StatementInterface prepare($sql) Prepares a SQL statement to be executed.
  *    {@see \Cake\Database\Connnection::prepare()}
  * @method \Cake\Database\StatementInterface execute($query, $params = [], array $types = []) Executes a query using
@@ -42,6 +40,16 @@
  */
 interface ConnectionInterface extends LoggerAwareInterface
 {
+    /**
+     * @var string
+     */
+    public const ROLE_WRITE = 'write';
+
+    /**
+     * @var string
+     */
+    public const ROLE_READ = 'read';
+
     /**
      * Gets the current logger object.
      *
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php
index 54adf540f..8f244ea16 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php
@@ -43,7 +43,7 @@ class ConnectionManager
     /**
      * A map of connection aliases.
      *
-     * @var array
+     * @var array
      */
     protected static $_aliasMap = [];
 
@@ -63,7 +63,7 @@ class ConnectionManager
     /**
      * The ConnectionRegistry used by the manager.
      *
-     * @var \Cake\Datasource\ConnectionRegistry
+     * @var \Cake\Datasource\ConnectionRegistry|null
      */
     protected static $_registry;
 
@@ -173,6 +173,16 @@ public static function dropAlias(string $alias): void
         unset(static::$_aliasMap[$alias]);
     }
 
+    /**
+     * Returns the current connection aliases and what they alias.
+     *
+     * @return array
+     */
+    public static function aliases(): array
+    {
+        return static::$_aliasMap;
+    }
+
     /**
      * Get a connection.
      *
@@ -182,8 +192,8 @@ public static function dropAlias(string $alias): void
      * as second parameter.
      *
      * @param string $name The connection name.
-     * @param bool $useAliases Set to false to not use aliased connections.
-     * @return \Cake\Datasource\ConnectionInterface A connection object.
+     * @param bool $useAliases Whether connection aliases are used
+     * @return \Cake\Datasource\ConnectionInterface
      * @throws \Cake\Datasource\Exception\MissingDatasourceConfigException When config
      * data is missing.
      */
@@ -192,15 +202,15 @@ public static function get(string $name, bool $useAliases = true)
         if ($useAliases && isset(static::$_aliasMap[$name])) {
             $name = static::$_aliasMap[$name];
         }
-        if (empty(static::$_config[$name])) {
+
+        if (!isset(static::$_config[$name])) {
             throw new MissingDatasourceConfigException(['name' => $name]);
         }
-        /** @psalm-suppress RedundantPropertyInitializationCheck */
+
         if (!isset(static::$_registry)) {
             static::$_registry = new ConnectionRegistry();
         }
 
-        return static::$_registry->{$name}
-            ?? static::$_registry->load($name, static::$_config[$name]);
+        return static::$_registry->{$name} ?? static::$_registry->load($name, static::$_config[$name]);
     }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php
index c0991064b..58876709b 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php
@@ -25,6 +25,7 @@
  *
  * @property mixed $id Alias for commonly used primary key.
  * @method bool[] getAccessible() Accessible configuration for this entity.
+ * @template-extends \ArrayAccess
  */
 interface EntityInterface extends ArrayAccess, JsonSerializable
 {
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php b/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php
index b8ef4a9dd..3cd54bb1a 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php
@@ -22,6 +22,7 @@
 use Cake\Utility\Inflector;
 use InvalidArgumentException;
 use Traversable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * An entity represents a single result row from a repository. It exposes the
@@ -118,6 +119,23 @@ trait EntityTrait
      */
     protected $_registryAlias = '';
 
+    /**
+     * Storing the current visitation status while recursing through entities getting errors.
+     *
+     * @var bool
+     */
+    protected $_hasBeenVisited = false;
+
+    /**
+     * Set to true in your entity's class definition or
+     * via application logic. When true. has() and related
+     * methods will use `array_key_exists` instead of `isset`
+     * to decide if fields are 'defined' in an entity.
+     *
+     * @var bool
+     */
+    protected $_hasAllowsNull = false;
+
     /**
      * Magic getter to access fields that have been set in this entity
      *
@@ -361,7 +379,11 @@ public function getOriginalValues(): array
     public function has($field): bool
     {
         foreach ((array)$field as $prop) {
-            if ($this->get($prop) === null) {
+            if ($this->_hasAllowsNull) {
+                if (!array_key_exists($prop, $this->_fields) && !static::_accessor($prop, 'get')) {
+                    return false;
+                }
+            } elseif ($this->get($prop) === null) {
                 return false;
             }
         }
@@ -845,6 +867,11 @@ public function isNew(): bool
      */
     public function hasErrors(bool $includeNested = true): bool
     {
+        if ($this->_hasBeenVisited) {
+            // While recursing through entities, each entity should only be visited once. See https://github.com/cakephp/cakephp/issues/17318
+            return false;
+        }
+
         if (Hash::filter($this->_errors)) {
             return true;
         }
@@ -853,10 +880,15 @@ public function hasErrors(bool $includeNested = true): bool
             return false;
         }
 
-        foreach ($this->_fields as $field) {
-            if ($this->_readHasErrors($field)) {
-                return true;
+        $this->_hasBeenVisited = true;
+        try {
+            foreach ($this->_fields as $field) {
+                if ($this->_readHasErrors($field)) {
+                    return true;
+                }
             }
+        } finally {
+            $this->_hasBeenVisited = false;
         }
 
         return false;
@@ -869,17 +901,29 @@ public function hasErrors(bool $includeNested = true): bool
      */
     public function getErrors(): array
     {
+        if ($this->_hasBeenVisited) {
+            // While recursing through entities, each entity should only be visited once. See https://github.com/cakephp/cakephp/issues/17318
+            return [];
+        }
+
         $diff = array_diff_key($this->_fields, $this->_errors);
 
-        return $this->_errors + (new Collection($diff))
-            ->filter(function ($value) {
-                return is_array($value) || $value instanceof EntityInterface;
-            })
-            ->map(function ($value) {
-                return $this->_readError($value);
-            })
-            ->filter()
-            ->toArray();
+        $this->_hasBeenVisited = true;
+        try {
+            $errors = $this->_errors + (new Collection($diff))
+                ->filter(function ($value) {
+                    return is_array($value) || $value instanceof EntityInterface;
+                })
+                ->map(function ($value) {
+                    return $this->_readError($value);
+                })
+                ->filter()
+                ->toArray();
+        } finally {
+            $this->_hasBeenVisited = false;
+        }
+
+        return $errors;
     }
 
     /**
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php b/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php
index be75b2d76..a841303dd 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php
@@ -1,7 +1,10 @@
 {$alias})) {
             return $this->{$alias};
@@ -135,6 +142,60 @@ public function loadModel(?string $modelClass = null, ?string $modelType = null)
         return $this->{$alias};
     }
 
+    /**
+     * Fetch or construct a model instance from a locator.
+     *
+     * Uses a modelFactory based on `$modelType` to fetch and construct a `RepositoryInterface`
+     * and return it. The default `modelType` can be defined with `setModelType()`.
+     *
+     * Unlike `loadModel()` this method will *not* set an object property.
+     *
+     * If a repository provider does not return an object a MissingModelException will
+     * be thrown.
+     *
+     * @param string|null $modelClass Name of model class to load. Defaults to $this->modelClass.
+     *  The name can be an alias like `'Post'` or FQCN like `App\Model\Table\PostsTable::class`.
+     * @param string|null $modelType The type of repository to load. Defaults to the getModelType() value.
+     * @return \Cake\Datasource\RepositoryInterface The model instance created.
+     * @throws \Cake\Datasource\Exception\MissingModelException If the model class cannot be found.
+     * @throws \UnexpectedValueException If $modelClass argument is not provided
+     *   and ModelAwareTrait::$modelClass property value is empty.
+     */
+    public function fetchModel(?string $modelClass = null, ?string $modelType = null): RepositoryInterface
+    {
+        $modelClass = $modelClass ?? $this->modelClass;
+        if (empty($modelClass)) {
+            throw new UnexpectedValueException('Default modelClass is empty');
+        }
+        $modelType = $modelType ?? $this->getModelType();
+
+        $options = [];
+        if (strpos($modelClass, '\\') === false) {
+            [, $alias] = pluginSplit($modelClass, true);
+        } else {
+            $options['className'] = $modelClass;
+            /** @psalm-suppress PossiblyFalseOperand */
+            $alias = substr(
+                $modelClass,
+                strrpos($modelClass, '\\') + 1,
+                -strlen($modelType)
+            );
+            $modelClass = $alias;
+        }
+
+        $factory = $this->_modelFactories[$modelType] ?? FactoryLocator::get($modelType);
+        if ($factory instanceof LocatorInterface) {
+            $instance = $factory->get($modelClass, $options);
+        } else {
+            $instance = $factory($modelClass, $options);
+        }
+        if ($instance) {
+            return $instance;
+        }
+
+        throw new MissingModelException([$modelClass, $modelType]);
+    }
+
     /**
      * Override a existing callable to generate repositories of a given type.
      *
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php b/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php
index a87c8ea62..926b2318f 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php
@@ -1,7 +1,10 @@
  20,
         'maxLimit' => 100,
         'allowedParameters' => ['limit', 'sort', 'page', 'direction'],
+        'sortableFields' => null,
+        'finder' => 'all',
     ];
 
     /**
@@ -214,10 +217,17 @@ public function paginate(object $object, array $params = [], array $settings = [
      */
     protected function getQuery(RepositoryInterface $object, ?QueryInterface $query, array $data): QueryInterface
     {
+        $options = $data['options'];
+        unset(
+            $options['scope'],
+            $options['sort'],
+            $options['direction'],
+        );
+
         if ($query === null) {
-            $query = $object->find($data['finder'], $data['options']);
+            $query = $object->find($data['finder'], $options);
         } else {
-            $query->applyOptions($data['options']);
+            $query->applyOptions($options);
         }
 
         return $query;
@@ -247,6 +257,20 @@ protected function extractData(RepositoryInterface $object, array $params, array
     {
         $alias = $object->getAlias();
         $defaults = $this->getDefaults($alias, $settings);
+
+        $validSettings = array_merge(
+            array_keys($this->_defaultConfig),
+            ['whitelist', 'sortWhitelist', 'order', 'scope']
+        );
+        $extraSettings = array_diff_key($defaults, array_flip($validSettings));
+        if ($extraSettings) {
+            deprecationWarning(
+                'Passing query options as paginator settings is deprecated.'
+                . ' Use a custom finder through `finder` config instead.'
+                . ' Extra keys found are: ' . implode(',', array_keys($extraSettings))
+            );
+        }
+
         $options = $this->mergeOptions($params, $defaults);
         $options = $this->validateSort($object, $options);
         $options = $this->checkLimit($options);
@@ -396,7 +420,14 @@ protected function addSortingParams(array $params, array $data): array
     protected function _extractFinder(array $options): array
     {
         $type = !empty($options['finder']) ? $options['finder'] : 'all';
-        unset($options['finder'], $options['maxLimit']);
+        unset(
+            $options['finder'],
+            $options['maxLimit'],
+            $options['allowedParameters'],
+            $options['whitelist'],
+            $options['sortableFields'],
+            $options['sortWhitelist'],
+        );
 
         if (is_array($type)) {
             $options = (array)current($type) + $options;
@@ -611,6 +642,13 @@ protected function _removeAliases(array $fields, string $model): array
     {
         $result = [];
         foreach ($fields as $field => $sort) {
+            if (is_int($field)) {
+                throw new CakeException(sprintf(
+                    'The `order` config must be an associative array. Found invalid value with numeric key: `%s`',
+                    $sort
+                ));
+            }
+
             if (strpos($field, '.') === false) {
                 $result[$field] = $sort;
                 continue;
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php
index 3c34bdf8d..47fede090 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php
@@ -24,6 +24,7 @@
  *   provided list using the AND operator. {@see \Cake\Database\Query::andWhere()}
  * @method \Cake\Datasource\EntityInterface|array firstOrFail() Get the first result from the executing query or raise an exception.
  *   {@see \Cake\Database\Query::firstOrFail()}
+ * @method $this setRepository(\Cake\Datasource\RepositoryInterface $repository) Set the default repository object that will be used by this query.
  */
 interface QueryInterface
 {
@@ -278,6 +279,7 @@ public function toArray(): array;
      *
      * @param \Cake\Datasource\RepositoryInterface $repository The default repository object to use
      * @return $this
+     * @deprecated
      */
     public function repository(RepositoryInterface $repository);
 
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php b/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php
index 6d70a77b5..15525612e 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php
@@ -17,10 +17,12 @@
 namespace Cake\Datasource;
 
 use BadMethodCallException;
+use Cake\Collection\CollectionInterface;
 use Cake\Collection\Iterator\MapReduce;
 use Cake\Datasource\Exception\RecordNotFoundException;
 use InvalidArgumentException;
 use Traversable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Contains the characteristics for an object that is attached to a repository and
@@ -89,8 +91,23 @@ trait QueryTrait
      *
      * @param \Cake\Datasource\RepositoryInterface|\Cake\ORM\Table $repository The default table object to use
      * @return $this
+     * @deprecated 4.5.0 Use `setRepository()` instead.
      */
     public function repository(RepositoryInterface $repository)
+    {
+        deprecationWarning('`repository() method is deprecated. Use `setRepository()` instead.');
+
+        return $this->setRepository($repository);
+    }
+
+    /**
+     * Set the default Table object that will be used by this query
+     * and form the `FROM` clause.
+     *
+     * @param \Cake\Datasource\RepositoryInterface|\Cake\ORM\Table $repository The default table object to use
+     * @return $this
+     */
+    public function setRepository(RepositoryInterface $repository)
     {
         $this->_repository = $repository;
 
@@ -564,6 +581,833 @@ public function __call(string $method, array $arguments)
         );
     }
 
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::each()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function each(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling each() on a Query is deprecated. ' .
+            'Instead call `$query->all()->each(...)` instead.'
+        );
+
+        return $this->all()->each($callback);
+    }
+
+    /**
+     * @param ?callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::filter()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function filter(?callable $callback = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling filter() on a Query is deprecated. ' .
+            'Instead call `$query->all()->filter(...)` instead.'
+        );
+
+        return $this->all()->filter($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::reject()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function reject(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling reject() on a Query is deprecated. ' .
+            'Instead call `$query->all()->reject(...)` instead.'
+        );
+
+        return $this->all()->reject($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::every()
+     * @return bool
+     * @deprecated
+     */
+    public function every(callable $callback): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling every() on a Query is deprecated. ' .
+            'Instead call `$query->all()->every(...)` instead.'
+        );
+
+        return $this->all()->every($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::some()
+     * @return bool
+     * @deprecated
+     */
+    public function some(callable $callback): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling some() on a Query is deprecated. ' .
+            'Instead call `$query->all()->some(...)` instead.'
+        );
+
+        return $this->all()->some($callback);
+    }
+
+    /**
+     * @param mixed $value The value to check.
+     * @see \Cake\Collection\CollectionInterface::contains()
+     * @return bool
+     * @deprecated
+     */
+    public function contains($value): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling contains() on a Query is deprecated. ' .
+            'Instead call `$query->all()->contains(...)` instead.'
+        );
+
+        return $this->all()->contains($value);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::map()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function map(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling map() on a Query is deprecated. ' .
+            'Instead call `$query->all()->map(...)` instead.'
+        );
+
+        return $this->all()->map($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @param mixed $initial The initial value
+     * @see \Cake\Collection\CollectionInterface::reduce()
+     * @return mixed
+     * @deprecated
+     */
+    public function reduce(callable $callback, $initial = null)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling reduce() on a Query is deprecated. ' .
+            'Instead call `$query->all()->reduce(...)` instead.'
+        );
+
+        return $this->all()->reduce($callback, $initial);
+    }
+
+    /**
+     * @param callable|string $path The path to extract
+     * @see \Cake\Collection\CollectionInterface::extract()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function extract($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling extract() on a Query is deprecated. ' .
+            'Instead call `$query->all()->extract(...)` instead.'
+        );
+
+        return $this->all()->extract($path);
+    }
+
+    /**
+     * @param callable|string $path The path to max
+     * @param int $sort The SORT_ constant to order by.
+     * @see \Cake\Collection\CollectionInterface::max()
+     * @return mixed
+     * @deprecated
+     */
+    public function max($path, int $sort = \SORT_NUMERIC)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling max() on a Query is deprecated. ' .
+            'Instead call `$query->all()->max(...)` instead.'
+        );
+
+        return $this->all()->max($path, $sort);
+    }
+
+    /**
+     * @param callable|string $path The path to max
+     * @param int $sort The SORT_ constant to order by.
+     * @see \Cake\Collection\CollectionInterface::min()
+     * @return mixed
+     * @deprecated
+     */
+    public function min($path, int $sort = \SORT_NUMERIC)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling min() on a Query is deprecated. ' .
+            'Instead call `$query->all()->min(...)` instead.'
+        );
+
+        return $this->all()->min($path, $sort);
+    }
+
+    /**
+     * @param callable|string|null $path the path to average
+     * @see \Cake\Collection\CollectionInterface::avg()
+     * @return float|int|null
+     * @deprecated
+     */
+    public function avg($path = null)
+    {
+        deprecationwarning(
+            '4.3.0 - calling avg() on a query is deprecated. ' .
+            'instead call `$query->all()->avg(...)` instead.'
+        );
+
+        return $this->all()->avg($path);
+    }
+
+    /**
+     * @param callable|string|null $path the path to average
+     * @see \Cake\Collection\CollectionInterface::median()
+     * @return float|int|null
+     * @deprecated
+     */
+    public function median($path = null)
+    {
+        deprecationwarning(
+            '4.3.0 - calling median() on a query is deprecated. ' .
+            'instead call `$query->all()->median(...)` instead.'
+        );
+
+        return $this->all()->median($path);
+    }
+
+    /**
+     * @param callable|string $path the path to average
+     * @param int $order The \SORT_ constant for the direction you want results in.
+     * @param int $sort The \SORT_ method to use.
+     * @see \Cake\Collection\CollectionInterface::sortBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function sortBy($path, int $order = SORT_DESC, int $sort = \SORT_NUMERIC): CollectionInterface
+    {
+        deprecationwarning(
+            '4.3.0 - calling sortBy() on a query is deprecated. ' .
+            'instead call `$query->all()->sortBy(...)` instead.'
+        );
+
+        return $this->all()->sortBy($path, $order, $sort);
+    }
+
+    /**
+     * @param callable|string $path The path to group by
+     * @see \Cake\Collection\CollectionInterface::groupBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function groupBy($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling groupBy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->groupBy(...)` instead.'
+        );
+
+        return $this->all()->groupBy($path);
+    }
+
+    /**
+     * @param string|callable $path The path to extract
+     * @see \Cake\Collection\CollectionInterface::indexBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function indexBy($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling indexBy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->indexBy(...)` instead.'
+        );
+
+        return $this->all()->indexBy($path);
+    }
+
+    /**
+     * @param string|callable $path The path to count by
+     * @see \Cake\Collection\CollectionInterface::countBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function countBy($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling countBy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->countBy(...)` instead.'
+        );
+
+        return $this->all()->countBy($path);
+    }
+
+    /**
+     * @param string|callable $path The path to sum
+     * @see \Cake\Collection\CollectionInterface::sumOf()
+     * @return int|float
+     * @deprecated
+     */
+    public function sumOf($path = null)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling sumOf() on a Query is deprecated. ' .
+                'Instead call `$query->all()->sumOf(...)` instead.'
+        );
+
+        return $this->all()->sumOf($path);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::shuffle()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function shuffle(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling shuffle() on a Query is deprecated. ' .
+            'Instead call `$query->all()->shuffle(...)` instead.'
+        );
+
+        return $this->all()->shuffle();
+    }
+
+    /**
+     * @param int $length The number of samples to select
+     * @see \Cake\Collection\CollectionInterface::sample()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function sample(int $length = 10): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling sample() on a Query is deprecated. ' .
+            'Instead call `$query->all()->sample(...)` instead.'
+        );
+
+        return $this->all()->sample($length);
+    }
+
+    /**
+     * @param int $length The number of elements to take
+     * @param int $offset The offset of the first element to take.
+     * @see \Cake\Collection\CollectionInterface::take()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function take(int $length = 1, int $offset = 0): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling take() on a Query is deprecated. ' .
+            'Instead call `$query->all()->take(...)` instead.'
+        );
+
+        return $this->all()->take($length, $offset);
+    }
+
+    /**
+     * @param int $length The number of items to take.
+     * @see \Cake\Collection\CollectionInterface::takeLast()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function takeLast(int $length): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling takeLast() on a Query is deprecated. ' .
+            'Instead call `$query->all()->takeLast(...)` instead.'
+        );
+
+        return $this->all()->takeLast($length);
+    }
+
+    /**
+     * @param int $length The number of items to skip
+     * @see \Cake\Collection\CollectionInterface::skip()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function skip(int $length): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling skip() on a Query is deprecated. ' .
+            'Instead call `$query->all()->skip(...)` instead.'
+        );
+
+        return $this->all()->skip($length);
+    }
+
+    /**
+     * @param array $conditions The conditions to use.
+     * @see \Cake\Collection\CollectionInterface::match()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function match(array $conditions): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling match() on a Query is deprecated. ' .
+            'Instead call `$query->all()->match(...)` instead.'
+        );
+
+        return $this->all()->match($conditions);
+    }
+
+    /**
+     * @param array $conditions The conditions to apply
+     * @see \Cake\Collection\CollectionInterface::firstMatch()
+     * @return mixed
+     * @deprecated
+     */
+    public function firstMatch(array $conditions)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling firstMatch() on a Query is deprecated. ' .
+            'Instead call `$query->all()->firstMatch(...)` instead.'
+        );
+
+        return $this->all()->firstMatch($conditions);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::last()
+     * @deprecated
+     * @return mixed
+     */
+    public function last()
+    {
+        deprecationWarning(
+            '4.3.0 - Calling last() on a Query is deprecated. ' .
+            'Instead call `$query->all()->last(...)` instead.'
+        );
+
+        return $this->all()->last();
+    }
+
+    /**
+     * @param mixed $items The items to append
+     * @see \Cake\Collection\CollectionInterface::append()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function append($items): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling append() on a Query is deprecated. ' .
+            'Instead call `$query->all()->append(...)` instead.'
+        );
+
+        return $this->all()->append($items);
+    }
+
+    /**
+     * @param mixed $item The item to apply
+     * @param mixed $key The key to append with
+     * @see \Cake\Collection\CollectionInterface::appendItem()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function appendItem($item, $key = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling appendItem() on a Query is deprecated. ' .
+            'Instead call `$query->all()->appendItem(...)` instead.'
+        );
+
+        return $this->all()->appendItem($item, $key);
+    }
+
+    /**
+     * @param mixed $items The items to prepend.
+     * @see \Cake\Collection\CollectionInterface::prepend()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function prepend($items): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling prepend() on a Query is deprecated. ' .
+            'Instead call `$query->all()->prepend(...)` instead.'
+        );
+
+        return $this->all()->prepend($items);
+    }
+
+    /**
+     * @param mixed $item The item to prepend
+     * @param mixed $key The key to use.
+     * @see \Cake\Collection\CollectionInterface::prependItem()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function prependItem($item, $key = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling prependItem() on a Query is deprecated. ' .
+            'Instead call `$query->all()->prependItem(...)` instead.'
+        );
+
+        return $this->all()->prependItem($item, $key);
+    }
+
+    /**
+     * @param callable|string $keyPath The path for keys
+     * @param callable|string $valuePath The path for values
+     * @param callable|string|null $groupPath The path for grouping
+     * @see \Cake\Collection\CollectionInterface::combine()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function combine($keyPath, $valuePath, $groupPath = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling combine() on a Query is deprecated. ' .
+            'Instead call `$query->all()->combine(...)` instead.'
+        );
+
+        return $this->all()->combine($keyPath, $valuePath, $groupPath);
+    }
+
+    /**
+     * @param callable|string $idPath The path to ids
+     * @param callable|string $parentPath The path to parents
+     * @param string $nestingKey Key used for nesting children.
+     * @see \Cake\Collection\CollectionInterface::nest()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function nest($idPath, $parentPath, string $nestingKey = 'children'): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling nest() on a Query is deprecated. ' .
+            'Instead call `$query->all()->nest(...)` instead.'
+        );
+
+        return $this->all()->nest($idPath, $parentPath, $nestingKey);
+    }
+
+    /**
+     * @param string $path The path to insert on
+     * @param mixed $values The values to insert.
+     * @see \Cake\Collection\CollectionInterface::insert()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function insert(string $path, $values): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling insert() on a Query is deprecated. ' .
+            'Instead call `$query->all()->insert(...)` instead.'
+        );
+
+        return $this->all()->insert($path, $values);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::toList()
+     * @return array
+     * @deprecated
+     */
+    public function toList(): array
+    {
+        deprecationWarning(
+            '4.3.0 - Calling toList() on a Query is deprecated. ' .
+            'Instead call `$query->all()->toList(...)` instead.'
+        );
+
+        return $this->all()->toList();
+    }
+
+    /**
+     * @param bool $keepKeys Whether or not keys should be kept
+     * @see \Cake\Collection\CollectionInterface::compile()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function compile(bool $keepKeys = true): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling compile() on a Query is deprecated. ' .
+            'Instead call `$query->all()->compile(...)` instead.'
+        );
+
+        return $this->all()->compile($keepKeys);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::lazy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function lazy(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling lazy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->lazy(...)` instead.'
+        );
+
+        return $this->all()->lazy();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::buffered()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function buffered(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling buffered() on a Query is deprecated. ' .
+            'Instead call `$query->all()->buffered(...)` instead.'
+        );
+
+        return $this->all()->buffered();
+    }
+
+    /**
+     * @param string|int $order The order in which to return the elements
+     * @param callable|string $nestingKey The key name under which children are nested
+     * @see \Cake\Collection\CollectionInterface::listNested()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function listNested($order = 'desc', $nestingKey = 'children'): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling listNested() on a Query is deprecated. ' .
+            'Instead call `$query->all()->listNested(...)` instead.'
+        );
+
+        return $this->all()->listNested($order, $nestingKey);
+    }
+
+    /**
+     * @param callable|array $condition the method that will receive each of the elements and
+     *   returns true when the iteration should be stopped.
+     * @see \Cake\Collection\CollectionInterface::stopWhen()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function stopWhen($condition): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling stopWhen() on a Query is deprecated. ' .
+            'Instead call `$query->all()->stopWhen(...)` instead.'
+        );
+
+        return $this->all()->stopWhen($condition);
+    }
+
+    /**
+     * @param callable|null $callback A callable function that will receive each of
+     *  items in the collection.
+     * @see \Cake\Collection\CollectionInterface::unfold()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function unfold(?callable $callback = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling unfold() on a Query is deprecated. ' .
+            'Instead call `$query->all()->unfold(...)` instead.'
+        );
+
+        return $this->all()->unfold($callback);
+    }
+
+    /**
+     * @param callable $callback A callable function that will receive each of
+     *  items in the collection.
+     * @see \Cake\Collection\CollectionInterface::through()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function through(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling through() on a Query is deprecated. ' .
+            'Instead call `$query->all()->through(...)` instead.'
+        );
+
+        return $this->all()->through($callback);
+    }
+
+    /**
+     * @param iterable ...$items The collections to zip.
+     * @see \Cake\Collection\CollectionInterface::zip()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function zip(iterable $items): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling zip() on a Query is deprecated. ' .
+            'Instead call `$query->all()->zip(...)` instead.'
+        );
+
+        return $this->all()->zip($items);
+    }
+
+    /**
+     * @param iterable ...$items The collections to zip.
+     * @param callable $callback The function to use for zipping the elements together.
+     * @see \Cake\Collection\CollectionInterface::zipWith()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function zipWith(iterable $items, $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling zipWith() on a Query is deprecated. ' .
+            'Instead call `$query->all()->zipWith(...)` instead.'
+        );
+
+        return $this->all()->zipWith($items, $callback);
+    }
+
+    /**
+     * @param int $chunkSize The maximum size for each chunk
+     * @see \Cake\Collection\CollectionInterface::chunk()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function chunk(int $chunkSize): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling chunk() on a Query is deprecated. ' .
+            'Instead call `$query->all()->chunk(...)` instead.'
+        );
+
+        return $this->all()->chunk($chunkSize);
+    }
+
+    /**
+     * @param int $chunkSize The maximum size for each chunk
+     * @param bool $keepKeys If the keys of the array should be kept
+     * @see \Cake\Collection\CollectionInterface::chunkWithKeys()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function chunkWithKeys(int $chunkSize, bool $keepKeys = true): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling chunkWithKeys() on a Query is deprecated. ' .
+            'Instead call `$query->all()->chunkWithKeys(...)` instead.'
+        );
+
+        return $this->all()->chunkWithKeys($chunkSize, $keepKeys);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::isEmpty()
+     * @return bool
+     * @deprecated
+     */
+    public function isEmpty(): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling isEmpty() on a Query is deprecated. ' .
+            'Instead call `$query->all()->isEmpty(...)` instead.'
+        );
+
+        return $this->all()->isEmpty();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::unwrap()
+     * @return \Traversable
+     * @deprecated
+     */
+    public function unwrap(): Traversable
+    {
+        deprecationWarning(
+            '4.3.0 - Calling unwrap() on a Query is deprecated. ' .
+            'Instead call `$query->all()->unwrap(...)` instead.'
+        );
+
+        return $this->all()->unwrap();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::transpose()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function transpose(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling transpose() on a Query is deprecated. ' .
+            'Instead call `$query->all()->transpose(...)` instead.'
+        );
+
+        return $this->all()->transpose();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::count()
+     * @return int
+     * @deprecated
+     */
+    public function count(): int
+    {
+        deprecationWarning(
+            '4.3.0 - Calling count() on a Query is deprecated. ' .
+            'Instead call `$query->all()->count(...)` instead.'
+        );
+
+        return $this->all()->count();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::countKeys()
+     * @return int
+     * @deprecated
+     */
+    public function countKeys(): int
+    {
+        deprecationWarning(
+            '4.3.0 - Calling countKeys() on a Query is deprecated. ' .
+            'Instead call `$query->all()->countKeys(...)` instead.'
+        );
+
+        return $this->all()->countKeys();
+    }
+
+    /**
+     * @param callable|null $operation A callable that allows you to customize the product result.
+     * @param callable|null $filter A filtering callback that must return true for a result to be part
+     *   of the final results.
+     * @see \Cake\Collection\CollectionInterface::cartesianProduct()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function cartesianProduct(?callable $operation = null, ?callable $filter = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling cartesianProduct() on a Query is deprecated. ' .
+            'Instead call `$query->all()->cartesianProduct(...)` instead.'
+        );
+
+        return $this->all()->cartesianProduct($operation, $filter);
+    }
+
     /**
      * Populates or adds parts to current query clauses using an array.
      * This is handy for passing all query clauses at once.
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php
index e59e63e54..85d98b618 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php
@@ -17,11 +17,15 @@
 namespace Cake\Datasource;
 
 use Cake\Collection\Collection;
+use Cake\Core\Configure;
 use Countable;
 
 /**
  * Generic ResultSet decorator. This will make any traversable object appear to
  * be a database result
+ *
+ * @template T of \Cake\Datasource\EntityInterface|array
+ * @implements \Cake\Datasource\ResultSetInterface
  */
 class ResultSetDecorator extends Collection implements ResultSetInterface
 {
@@ -43,4 +47,15 @@ public function count(): int
 
         return count($this->toArray());
     }
+
+    /**
+     * @inheritDoc
+     */
+    public function __debugInfo(): array
+    {
+        $parentInfo = parent::__debugInfo();
+        $limit = Configure::read('App.ResultSetDebugLimit', 10);
+
+        return array_merge($parentInfo, ['items' => $this->take($limit)->toArray()]);
+    }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php
index a62ee77f3..c193fac81 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php
@@ -22,6 +22,8 @@
 
 /**
  * Describes how a collection of datasource results should look like
+ *
+ * @template T
  */
 interface ResultSetInterface extends CollectionInterface, Countable, Serializable
 {
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php b/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php
index 1bf5c9c37..c523eba5a 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php
@@ -112,7 +112,7 @@ class RulesChecker
     public function __construct(array $options = [])
     {
         $this->_options = $options;
-        $this->_useI18n = function_exists('__d');
+        $this->_useI18n = function_exists('\Cake\I18n\__d');
     }
 
     /**
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php b/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php
index 95499fb6d..134b0bd64 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php
@@ -1,7 +1,10 @@
 getTrace();
+        }
+        $parentFrames = $parent->getTrace();
+        $frames = $exception->getTrace();
+
+        $parentCount = count($parentFrames) - 1;
+        $frameCount = count($frames) - 1;
+
+        // Reverse loop through both traces removing frames that
+        // are the same.
+        for ($i = $frameCount, $p = $parentCount; $i >= 0 && $p >= 0; $p--) {
+            $parentTail = $parentFrames[$p];
+            $tail = $frames[$i];
+
+            // Frames without file/line are never equal to another frame.
+            $isEqual = (
+                (
+                    isset($tail['file']) &&
+                    isset($tail['line']) &&
+                    isset($parentTail['file']) &&
+                    isset($parentTail['line'])
+                ) &&
+                ($tail['file'] === $parentTail['file']) &&
+                ($tail['line'] === $parentTail['line'])
+            );
+            if ($isEqual) {
+                unset($frames[$i]);
+                $i--;
+            }
+        }
+
+        return $frames;
+    }
+
     /**
      * Outputs a stack trace based on the supplied options.
      *
@@ -390,7 +438,11 @@ public static function log($var, $level = 'debug', int $maxDepth = 3): void
      */
     public static function trace(array $options = [])
     {
-        return Debugger::formatTrace(debug_backtrace(), $options);
+        // Remove the frame for Debugger::trace()
+        $backtrace = debug_backtrace();
+        array_shift($backtrace);
+
+        return Debugger::formatTrace($backtrace, $options);
     }
 
     /**
@@ -426,60 +478,50 @@ public static function formatTrace($backtrace, array $options = [])
         ];
         $options = Hash::merge($defaults, $options);
 
-        $count = count($backtrace);
+        $count = count($backtrace) + 1;
         $back = [];
 
-        $_trace = [
-            'line' => '??',
-            'file' => '[internal]',
-            'class' => null,
-            'function' => '[main]',
-        ];
-
         for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) {
-            $trace = $backtrace[$i] + ['file' => '[internal]', 'line' => '??'];
-            $signature = $reference = '[main]';
-
-            if (isset($backtrace[$i + 1])) {
-                $next = $backtrace[$i + 1] + $_trace;
-                $signature = $reference = $next['function'];
-
-                if (!empty($next['class'])) {
-                    $signature = $next['class'] . '::' . $next['function'];
-                    $reference = $signature . '(';
-                    if ($options['args'] && isset($next['args'])) {
-                        $args = [];
-                        foreach ($next['args'] as $arg) {
-                            $args[] = Debugger::exportVar($arg);
-                        }
-                        $reference .= implode(', ', $args);
+            $frame = ['file' => '[main]', 'line' => ''];
+            if (isset($backtrace[$i])) {
+                $frame = $backtrace[$i] + ['file' => '[internal]', 'line' => '??'];
+            }
+
+            $signature = $reference = $frame['file'];
+            if (!empty($frame['class'])) {
+                $signature = $frame['class'] . $frame['type'] . $frame['function'];
+                $reference = $signature . '(';
+                if ($options['args'] && isset($frame['args'])) {
+                    $args = [];
+                    foreach ($frame['args'] as $arg) {
+                        $args[] = Debugger::exportVar($arg);
                     }
-                    $reference .= ')';
+                    $reference .= implode(', ', $args);
                 }
+                $reference .= ')';
             }
             if (in_array($signature, $options['exclude'], true)) {
                 continue;
             }
             if ($options['format'] === 'points') {
-                $back[] = ['file' => $trace['file'], 'line' => $trace['line'], 'reference' => $reference];
+                $back[] = ['file' => $frame['file'], 'line' => $frame['line'], 'reference' => $reference];
             } elseif ($options['format'] === 'array') {
                 if (!$options['args']) {
-                    unset($trace['args']);
+                    unset($frame['args']);
                 }
-                $back[] = $trace;
+                $back[] = $frame;
             } else {
-                if (isset($self->_templates[$options['format']]['traceLine'])) {
-                    $tpl = $self->_templates[$options['format']]['traceLine'];
+                $tpl = $self->_templates[$options['format']]['traceLine'] ?? $self->_templates['base']['traceLine'];
+                if ($frame['file'] == '[main]') {
+                    $back[] = '[main]';
                 } else {
-                    $tpl = $self->_templates['base']['traceLine'];
+                    $frame['path'] = static::trimPath($frame['file']);
+                    $frame['reference'] = $reference;
+                    unset($frame['object'], $frame['args']);
+                    $back[] = Text::insert($tpl, $frame, ['before' => '{:', 'after' => '}']);
                 }
-                $trace['path'] = static::trimPath($trace['file']);
-                $trace['reference'] = $reference;
-                unset($trace['object'], $trace['args']);
-                $back[] = Text::insert($tpl, $trace, ['before' => '{:', 'after' => '}']);
             }
         }
-
         if ($options['format'] === 'array' || $options['format'] === 'points') {
             return $back;
         }
@@ -575,9 +617,6 @@ public static function excerpt(string $file, int $line, int $context = 2): array
      */
     protected static function _highlight(string $str): string
     {
-        if (function_exists('hphp_log') || function_exists('hphp_gettid')) {
-            return htmlentities($str);
-        }
         $added = false;
         if (strpos($str, '', '<?php 
'], + ['<?php 
', '<?php 
', '<?php '], '', $highlight ); @@ -1119,7 +1158,7 @@ public static function printVar($var, array $location = [], ?bool $showHtml = nu * * - HTML escape the message. * - Convert `bool` into `bool` - * - Convert newlines into `
` + * - Convert newlines into `
` * * @param string $message The string message to format. * @return string Formatted message. diff --git a/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php b/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php index 76fdf1a81..ab2f54d04 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php +++ b/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php @@ -10,6 +10,7 @@ use Cake\Event\EventDispatcherTrait; use Cake\Routing\Router; use Exception; +use function Cake\Core\deprecationWarning; /** * Entry point to CakePHP's error handling. @@ -122,6 +123,17 @@ public function handleError( $trace = Debugger::trace(['start' => 1, 'format' => 'points']); $error = new PhpError($code, $description, $file, $line, $trace); + $ignoredPaths = (array)Configure::read('Error.ignoredDeprecationPaths'); + if ($code === E_USER_DEPRECATED && $ignoredPaths) { + $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', substr((string)$file, strlen(ROOT) + 1)); + foreach ($ignoredPaths as $pattern) { + $pattern = str_replace(DIRECTORY_SEPARATOR, '/', $pattern); + if (fnmatch($pattern, $relativePath)) { + return true; + } + } + } + $debug = Configure::read('debug'); $renderer = $this->renderer(); @@ -132,7 +144,7 @@ public function handleError( if ($event->isStopped()) { return true; } - $renderer->write($renderer->render($error, $debug)); + $renderer->write($event->getResult() ?: $renderer->render($error, $debug)); } catch (Exception $e) { // Fatal errors always log. $this->logger()->logMessage('error', 'Could not render error. Got: ' . $e->getMessage()); diff --git a/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php b/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php index f86155762..249cca920 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php +++ b/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php @@ -10,6 +10,8 @@ use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; use Throwable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\env; /** * Entry point to CakePHP's exception handling. @@ -237,8 +239,15 @@ public function handleException(Throwable $exception): void $this->logException($exception, $request); try { - $renderer = $this->renderer($exception); - $renderer->write($renderer->render()); + $event = $this->dispatchEvent('Exception.beforeRender', ['exception' => $exception, 'request' => $request]); + if ($event->isStopped()) { + return; + } + $exception = $event->getData('exception'); + assert($exception instanceof Throwable); + + $renderer = $this->renderer($exception, $request); + $renderer->write($event->getResult() ?: $renderer->render()); } catch (Throwable $exception) { $this->logInternalError($exception); } @@ -365,7 +374,6 @@ public function logException(Throwable $exception, ?ServerRequestInterface $requ $this->logger()->log($exception, $request); } } - $this->dispatchEvent('Exception.beforeRender', ['exception' => $exception]); } /** diff --git a/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php b/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php index d1e7efae7..b39ecc3f9 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php @@ -19,11 +19,15 @@ use Cake\Core\App; use Cake\Core\Configure; use Cake\Core\InstanceConfigTrait; +use Cake\Core\PluginApplicationInterface; use Cake\Error\ErrorHandler; use Cake\Error\ExceptionTrap; use Cake\Error\Renderer\WebExceptionRenderer; +use Cake\Event\EventDispatcherTrait; use Cake\Http\Exception\RedirectException; use Cake\Http\Response; +use Cake\Routing\Router; +use Cake\Routing\RoutingApplicationInterface; use InvalidArgumentException; use Laminas\Diactoros\Response\RedirectResponse; use Psr\Http\Message\ResponseInterface; @@ -31,6 +35,9 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Throwable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\Core\triggerWarning; /** * Error handling middleware. @@ -41,6 +48,7 @@ class ErrorHandlerMiddleware implements MiddlewareInterface { use InstanceConfigTrait; + use EventDispatcherTrait; /** * Default configuration values. @@ -72,22 +80,32 @@ class ErrorHandlerMiddleware implements MiddlewareInterface */ protected $exceptionTrap = null; + /** + * @var \Cake\Routing\RoutingApplicationInterface|null + */ + protected $app = null; + /** * Constructor * * @param \Cake\Error\ErrorHandler|\Cake\Error\ExceptionTrap|array $errorHandler The error handler instance * or config array. + * @param \Cake\Routing\RoutingApplicationInterface|null $app Application instance. * @throws \InvalidArgumentException */ - public function __construct($errorHandler = []) + public function __construct($errorHandler = [], $app = null) { if (func_num_args() > 1) { - deprecationWarning( - 'The signature of ErrorHandlerMiddleware::__construct() has changed. ' - . 'Pass the config array as 1st argument instead.' - ); + if (is_array($app)) { + deprecationWarning( + 'The signature of ErrorHandlerMiddleware::__construct() has changed. ' + . 'Pass the config array as 1st argument instead.' + ); - $errorHandler = func_get_arg(1); + $errorHandler = func_get_arg(1); + } else { + $this->app = $app; + } } if (PHP_VERSION_ID >= 70400 && Configure::read('debug')) { @@ -145,11 +163,24 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface */ public function handleException(Throwable $exception, ServerRequestInterface $request): ResponseInterface { + $this->loadRoutes(); + + $response = null; if ($this->errorHandler === null) { $handler = $this->getExceptionTrap(); $handler->logException($exception, $request); + $event = $this->dispatchEvent( + 'Exception.beforeRender', + ['exception' => $exception, 'request' => $request], + $handler + ); + + $exception = $event->getData('exception'); + assert($exception instanceof Throwable); $renderer = $handler->renderer($exception, $request); + + $response = $event->getResult(); } else { $handler = $this->getErrorHandler(); $handler->logException($exception, $request); @@ -158,13 +189,13 @@ public function handleException(Throwable $exception, ServerRequestInterface $re } try { - /** @var \Psr\Http\Message\ResponseInterface|string $response */ - $response = $renderer->render(); - if (is_string($response)) { - return new Response(['body' => $response, 'status' => 500]); + if ($response === null) { + $response = $renderer->render(); } - return $response; + return $response instanceof ResponseInterface + ? $response + : new Response(['body' => $response, 'status' => 500]); } catch (Throwable $internalException) { $handler->logException($internalException, $request); @@ -231,4 +262,34 @@ protected function getExceptionTrap(): ExceptionTrap return $this->exceptionTrap; } + + /** + * Ensure that the application's routes are loaded. + * + * @return void + */ + protected function loadRoutes(): void + { + if ( + !($this->app instanceof RoutingApplicationInterface) + || Router::routes() + ) { + return; + } + + try { + $builder = Router::createRouteBuilder('/'); + + $this->app->routes($builder); + if ($this->app instanceof PluginApplicationInterface) { + $this->app->pluginRoutes($builder); + } + } catch (Throwable $e) { + triggerWarning(sprintf( + "Exception loading routes when rendering an error page: \n %s - %s", + get_class($e), + $e->getMessage() + )); + } + } } diff --git a/app/vendor/cakephp/cakephp/src/Error/PhpError.php b/app/vendor/cakephp/cakephp/src/Error/PhpError.php index a0a5396fe..0b9944edb 100644 --- a/app/vendor/cakephp/cakephp/src/Error/PhpError.php +++ b/app/vendor/cakephp/cakephp/src/Error/PhpError.php @@ -183,7 +183,11 @@ public function getTraceAsString(): string { $out = []; foreach ($this->trace as $frame) { - $out[] = "{$frame['reference']} {$frame['file']}, line {$frame['line']}"; + if (!empty($frame['line'])) { + $out[] = "{$frame['reference']} {$frame['file']}, line {$frame['line']}"; + } else { + $out[] = $frame['reference']; + } } return implode("\n", $out); diff --git a/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php b/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php index 988dcfa44..cba448219 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php +++ b/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php @@ -19,6 +19,7 @@ use Cake\Console\ConsoleOutput; use Cake\Core\Configure; use Cake\Core\Exception\CakeException; +use Cake\Error\Debugger; use Psr\Http\Message\ServerRequestInterface; use Throwable; @@ -76,7 +77,8 @@ public function render() } $out = []; foreach ($exceptions as $i => $error) { - $out = array_merge($out, $this->renderException($error, $i)); + $parent = $exceptions[$i - 1] ?? null; + $out = array_merge($out, $this->renderException($error, $parent)); } return join("\n", $out); @@ -86,15 +88,15 @@ public function render() * Render an individual exception * * @param \Throwable $exception The exception to render. - * @param int $index Exception index in the chain + * @param ?\Throwable $parent The Exception index in the chain * @return array */ - protected function renderException(Throwable $exception, int $index): array + protected function renderException(Throwable $exception, ?Throwable $parent): array { $out = [ sprintf( '%s[%s] %s in %s on line %s', - $index > 0 ? 'Caused by ' : '', + $parent ? 'Caused by ' : '', get_class($exception), $exception->getMessage(), $exception->getFile(), @@ -114,10 +116,11 @@ protected function renderException(Throwable $exception, int $index): array } if ($this->trace) { + $stacktrace = Debugger::getUniqueFrames($exception, $parent); $out[] = ''; $out[] = 'Stack Trace:'; $out[] = ''; - $out[] = $exception->getTraceAsString(); + $out[] = Debugger::formatTrace($stacktrace, ['format' => 'txt']); $out[] = ''; } diff --git a/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php b/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php index 569445e0b..7e49178f5 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php +++ b/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php @@ -19,6 +19,7 @@ use Cake\Error\Debugger; use Cake\Error\ErrorRendererInterface; use Cake\Error\PhpError; +use function Cake\Core\h; /** * Interactive HTML error rendering with a stack trace. diff --git a/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php b/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php index 5c7143c1b..b249f7409 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php +++ b/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php @@ -44,6 +44,9 @@ use PDOException; use Psr\Http\Message\ResponseInterface; use Throwable; +use function Cake\Core\h; +use function Cake\Core\namespaceSplit; +use function Cake\I18n\__d; /** * Web Exception Renderer. @@ -167,9 +170,17 @@ protected function _getController(): Controller $params['controller'] = 'Error'; $factory = new ControllerFactory(new Container()); + // Check including plugin + prefix $class = $factory->getControllerClass($request->withAttribute('params', $params)); + if (!$class && !empty($params['prefix']) && !empty($params['plugin'])) { + unset($params['prefix']); + // Fallback to only plugin + $class = $factory->getControllerClass($request->withAttribute('params', $params)); + } + if (!$class) { + // Fallback to app/core provided controller. /** @var string $class */ $class = App::className('Error', 'Controller', 'Controller'); } diff --git a/app/vendor/cakephp/cakephp/src/Error/functions.php b/app/vendor/cakephp/cakephp/src/Error/functions.php new file mode 100644 index 000000000..6a33370a1 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Error/functions.php @@ -0,0 +1,117 @@ + 0, 'depth' => 1, 'format' => 'array']); + if (isset($trace[0]['line']) && isset($trace[0]['file'])) { + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + } + } + + Debugger::printVar($var, $location, $showHtml); + + return $var; +} + +/** + * Outputs a stack trace based on the supplied options. + * + * ### Options + * + * - `depth` - The number of stack frames to return. Defaults to 999 + * - `args` - Should arguments for functions be shown? If true, the arguments for each method call + * will be displayed. + * - `start` - The stack frame to start generating a trace from. Defaults to 1 + * + * @param array $options Format for outputting stack trace + * @return void + */ +function stackTrace(array $options = []): void +{ + if (!Configure::read('debug')) { + return; + } + + $options += ['start' => 0]; + $options['start']++; + + /** @var string $trace */ + $trace = Debugger::trace($options); + echo $trace; +} + +/** + * Prints out debug information about given variable and dies. + * + * Only runs if debug mode is enabled. + * It will otherwise just continue code execution and ignore this function. + * + * @param mixed $var Variable to show debug information for. + * @param bool|null $showHtml If set to true, the method prints the debug data in a browser-friendly way. + * @return void + * @link https://book.cakephp.org/4/en/development/debugging.html#basic-debugging + */ +function dd($var, $showHtml = null): void +{ + if (!Configure::read('debug')) { + return; + } + + $trace = Debugger::trace(['start' => 0, 'depth' => 2, 'format' => 'array']); + /** @psalm-suppress PossiblyInvalidArrayOffset */ + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + + Debugger::printVar($var, $location, $showHtml); + die(1); +} + +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; +} diff --git a/app/vendor/cakephp/cakephp/src/Error/functions_global.php b/app/vendor/cakephp/cakephp/src/Error/functions_global.php new file mode 100644 index 000000000..1f5ae23d8 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Error/functions_global.php @@ -0,0 +1,141 @@ + 0, 'depth' => 1, 'format' => 'array']); + if (isset($trace[0]['line']) && isset($trace[0]['file'])) { + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + } + } + + Debugger::printVar($var, $location, $showHtml); + + return $var; + } +} + +if (!function_exists('stackTrace')) { + /** + * Outputs a stack trace based on the supplied options. + * + * ### Options + * + * - `depth` - The number of stack frames to return. Defaults to 999 + * - `args` - Should arguments for functions be shown? If true, the arguments for each method call + * will be displayed. + * - `start` - The stack frame to start generating a trace from. Defaults to 1 + * + * @param array $options Format for outputting stack trace + * @return void + */ + function stackTrace(array $options = []): void + { + if (!Configure::read('debug')) { + return; + } + + $options += ['start' => 0]; + $options['start']++; + + /** @var string $trace */ + $trace = Debugger::trace($options); + echo $trace; + } +} + +if (!function_exists('dd')) { + /** + * Prints out debug information about given variable and dies. + * + * Only runs if debug mode is enabled. + * It will otherwise just continue code execution and ignore this function. + * + * @param mixed $var Variable to show debug information for. + * @param bool|null $showHtml If set to true, the method prints the debug data in a browser-friendly way. + * @return void + * @link https://book.cakephp.org/4/en/development/debugging.html#basic-debugging + */ + function dd($var, $showHtml = null): void + { + if (!Configure::read('debug')) { + return; + } + + $trace = Debugger::trace(['start' => 0, 'depth' => 2, 'format' => 'array']); + /** @psalm-suppress PossiblyInvalidArrayOffset */ + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + + Debugger::printVar($var, $location, $showHtml); + die(1); + } +} + +if (!function_exists('breakpoint')) { + /** + * Command to return the eval-able code to startup PsySH in interactive debugger + * Works the same way as eval(\Psy\sh()); + * psy/psysh must be loaded in your project + * + * ``` + * eval(breakpoint()); + * ``` + * + * @return string|null + * @link https://psysh.org/ + */ + function breakpoint(): ?string + { + if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && class_exists(PsyShell::class)) { + return 'extract(\Psy\Shell::debug(get_defined_vars(), isset($this) ? $this : null));'; + } + trigger_error( + 'psy/psysh must be installed and you must be in a CLI environment to use the breakpoint function', + E_USER_WARNING + ); + + return null; + } +} diff --git a/app/vendor/cakephp/cakephp/src/Event/EventList.php b/app/vendor/cakephp/cakephp/src/Event/EventList.php index e8cc40c93..00be78cd2 100644 --- a/app/vendor/cakephp/cakephp/src/Event/EventList.php +++ b/app/vendor/cakephp/cakephp/src/Event/EventList.php @@ -21,6 +21,8 @@ /** * The Event List + * + * @template-implements \ArrayAccess */ class EventList implements ArrayAccess, Countable { @@ -69,7 +71,7 @@ public function offsetExists($offset): bool * * @link https://secure.php.net/manual/en/arrayaccess.offsetget.php * @param mixed $offset The offset to retrieve. - * @return mixed Can return all value types. + * @return \Cake\Event\EventInterface|null */ #[\ReturnTypeWillChange] public function offsetGet($offset) diff --git a/app/vendor/cakephp/cakephp/src/Form/Form.php b/app/vendor/cakephp/cakephp/src/Form/Form.php index 9e8122359..29f8b198b 100644 --- a/app/vendor/cakephp/cakephp/src/Form/Form.php +++ b/app/vendor/cakephp/cakephp/src/Form/Form.php @@ -23,6 +23,7 @@ use Cake\Utility\Hash; use Cake\Validation\ValidatorAwareInterface; use Cake\Validation\ValidatorAwareTrait; +use function Cake\Core\deprecationWarning; /** * Form abstraction used to create forms not tied to ORM backed models, @@ -234,6 +235,17 @@ public function getErrors(): array return $this->_errors; } + /** + * Returns validation errors for the given field + * + * @param string $field Field name to get the errors from. + * @return array The validation errors for the given field. + */ + public function getError(string $field): array + { + return $this->_errors[$field] ?? []; + } + /** * Set the errors in the form. * diff --git a/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php b/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php index a8c381db3..3f2dbaf84 100644 --- a/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php +++ b/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php @@ -18,6 +18,7 @@ namespace Cake\Http; use Cake\Console\CommandCollection; +use Cake\Controller\ComponentRegistry; use Cake\Controller\ControllerFactory; use Cake\Core\ConsoleApplicationInterface; use Cake\Core\Container; @@ -306,6 +307,7 @@ public function handle( ): ResponseInterface { $container = $this->getContainer(); $container->add(ServerRequest::class, $request); + $container->add(ContainerInterface::class, $container); if ($this->controllerFactory === null) { $this->controllerFactory = new ControllerFactory($container); @@ -317,6 +319,9 @@ public function handle( $controller = $this->controllerFactory->create($request); + // This is needed for auto-wiring. Should be removed in 5.x + $container->add(ComponentRegistry::class, $controller->components()); + return $this->controllerFactory->invoke($controller); } } diff --git a/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php b/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php index 4ceed68e4..8289c19df 100644 --- a/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php +++ b/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php @@ -40,7 +40,6 @@ public function getContents(): string { $callback = $this->detach(); $result = ''; - /** @psalm-suppress TypeDoesNotContainType */ if ($callback !== null) { $result = $callback(); } diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php index 15ee3bf21..4ec86236d 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php @@ -21,6 +21,7 @@ use Closure; use InvalidArgumentException; use Psr\Http\Message\RequestInterface; +use function Cake\Core\getTypeName; /** * Implements sending requests to an array of stubbed responses diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php index d77fb0a6d..fcddd89d0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php @@ -314,7 +314,6 @@ protected function _open(string $url, RequestInterface $request): void return true; }); try { - /** @psalm-suppress PossiblyNullArgument */ $this->_stream = fopen($url, 'rb', false, $this->_context); } finally { restore_error_handler(); diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php b/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php index 577b1b78f..41e8903c3 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php @@ -17,6 +17,8 @@ use Cake\Http\Client; use Cake\Http\Client\Request; +use Cake\Http\HeaderUtility; +use Cake\Utility\Hash; /** * Digest authentication adapter for Cake\Http\Client @@ -26,6 +28,33 @@ */ class Digest { + /** + * Algorithms + */ + public const ALGO_MD5 = 'MD5'; + public const ALGO_SHA_256 = 'SHA-256'; + public const ALGO_SHA_512_256 = 'SHA-512-256'; + public const ALGO_MD5_SESS = 'MD5-sess'; + public const ALGO_SHA_256_SESS = 'SHA-256-sess'; + public const ALGO_SHA_512_256_SESS = 'SHA-512-256-sess'; + + /** + * QOP + */ + public const QOP_AUTH = 'auth'; + public const QOP_AUTH_INT = 'auth-int'; + + /** + * Algorithms <-> Hash type + */ + public const HASH_ALGORITHMS = [ + self::ALGO_MD5 => 'md5', + self::ALGO_SHA_256 => 'sha256', + self::ALGO_SHA_512_256 => 'sha512/256', + self::ALGO_MD5_SESS => 'md5', + self::ALGO_SHA_256_SESS => 'sha256', + self::ALGO_SHA_512_256_SESS => 'sha512/256', + ]; /** * Instance of Cake\Http\Client * @@ -33,6 +62,27 @@ class Digest */ protected $_client; + /** + * Algorithm + * + * @var string + */ + protected $algorithm; + + /** + * Hash type + * + * @var string + */ + protected $hashType; + + /** + * Is Sess algorithm + * + * @var bool + */ + protected $isSessAlgorithm; + /** * Constructor * @@ -44,6 +94,24 @@ public function __construct(Client $client, ?array $options = null) $this->_client = $client; } + /** + * Set algorithm based on credentials + * + * @param array $credentials authentication params + * @return void + */ + protected function setAlgorithm(array $credentials): void + { + $algorithm = $credentials['algorithm'] ?? self::ALGO_MD5; + if (!isset(self::HASH_ALGORITHMS[$algorithm])) { + throw new \InvalidArgumentException('Invalid Algorithm. Valid ones are: ' . + implode(',', array_keys(self::HASH_ALGORITHMS))); + } + $this->algorithm = $algorithm; + $this->isSessAlgorithm = strpos($this->algorithm, '-sess') !== false; + $this->hashType = Hash::get(self::HASH_ALGORITHMS, $this->algorithm); + } + /** * Add Authorization header to the request. * @@ -63,6 +131,8 @@ public function authentication(Request $request, array $credentials): Request if (!isset($credentials['realm'])) { return $request; } + + $this->setAlgorithm($credentials); $value = $this->_generateHeader($request, $credentials); return $request->withHeader('Authorization', $value); @@ -87,25 +157,28 @@ protected function _getServerInfo(Request $request, array $credentials): array ['auth' => ['type' => null]] ); - if (!$response->getHeader('WWW-Authenticate')) { + $header = $response->getHeader('WWW-Authenticate'); + if (!$header) { return []; } - preg_match_all( - '@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', - $response->getHeaderLine('WWW-Authenticate'), - $matches, - PREG_SET_ORDER - ); - foreach ($matches as $match) { - $credentials[$match[1]] = $match[2]; - } - if (!empty($credentials['qop']) && empty($credentials['nc'])) { + $matches = HeaderUtility::parseWwwAuthenticate($header[0]); + $credentials = array_merge($credentials, $matches); + + if (($this->isSessAlgorithm || !empty($credentials['qop'])) && empty($credentials['nc'])) { $credentials['nc'] = 1; } return $credentials; } + /** + * @return string + */ + protected function generateCnonce(): string + { + return uniqid(); + } + /** * Generate the header Authorization * @@ -115,18 +188,39 @@ protected function _getServerInfo(Request $request, array $credentials): array */ protected function _generateHeader(Request $request, array $credentials): string { - $path = $request->getUri()->getPath(); - $a1 = md5($credentials['username'] . ':' . $credentials['realm'] . ':' . $credentials['password']); - $a2 = md5($request->getMethod() . ':' . $path); - $nc = ''; + $path = $request->getRequestTarget(); + + if ($this->isSessAlgorithm) { + $credentials['cnonce'] = $this->generateCnonce(); + $a1 = hash($this->hashType, $credentials['username'] . ':' . + $credentials['realm'] . ':' . $credentials['password']) . ':' . + $credentials['nonce'] . ':' . $credentials['cnonce']; + } else { + $a1 = $credentials['username'] . ':' . $credentials['realm'] . ':' . $credentials['password']; + } + $ha1 = hash($this->hashType, $a1); + $a2 = $request->getMethod() . ':' . $path; + $nc = sprintf('%08x', $credentials['nc'] ?? 1); if (empty($credentials['qop'])) { - $response = md5($a1 . ':' . $credentials['nonce'] . ':' . $a2); + $ha2 = hash($this->hashType, $a2); + $response = hash($this->hashType, $ha1 . ':' . $credentials['nonce'] . ':' . $ha2); } else { - $credentials['cnonce'] = uniqid(); - $nc = sprintf('%08x', $credentials['nc']++); - $response = md5( - $a1 . ':' . $credentials['nonce'] . ':' . $nc . ':' . $credentials['cnonce'] . ':auth:' . $a2 + if (!in_array($credentials['qop'], [self::QOP_AUTH, self::QOP_AUTH_INT])) { + throw new \InvalidArgumentException('Invalid QOP parameter. Valid types are: ' . + implode(',', [self::QOP_AUTH, self::QOP_AUTH_INT])); + } + if ($credentials['qop'] === self::QOP_AUTH_INT) { + $a2 = $request->getMethod() . ':' . $path . ':' . hash($this->hashType, (string)$request->getBody()); + } + if (empty($credentials['cnonce'])) { + $credentials['cnonce'] = $this->generateCnonce(); + } + $ha2 = hash($this->hashType, $a2); + $response = hash( + $this->hashType, + $ha1 . ':' . $credentials['nonce'] . ':' . $nc . ':' . + $credentials['cnonce'] . ':' . $credentials['qop'] . ':' . $ha2 ); } @@ -135,13 +229,19 @@ protected function _generateHeader(Request $request, array $credentials): string $authHeader .= 'realm="' . $credentials['realm'] . '", '; $authHeader .= 'nonce="' . $credentials['nonce'] . '", '; $authHeader .= 'uri="' . $path . '", '; - $authHeader .= 'response="' . $response . '"'; + $authHeader .= 'algorithm="' . $this->algorithm . '"'; + + if (!empty($credentials['qop'])) { + $authHeader .= ', qop=' . $credentials['qop']; + } + if ($this->isSessAlgorithm || !empty($credentials['qop'])) { + $authHeader .= ', nc=' . $nc . ', cnonce="' . $credentials['cnonce'] . '"'; + } + $authHeader .= ', response="' . $response . '"'; + if (!empty($credentials['opaque'])) { $authHeader .= ', opaque="' . $credentials['opaque'] . '"'; } - if (!empty($credentials['qop'])) { - $authHeader .= ', qop="auth", nc=' . $nc . ', cnonce="' . $credentials['cnonce'] . '"'; - } return $authHeader; } diff --git a/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php b/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php index e02e78b0d..9db0c5530 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php +++ b/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php @@ -51,37 +51,7 @@ public function parseAcceptLanguage(RequestInterface $request): array */ protected function parseQualifiers(string $header): array { - $accept = []; - if (!$header) { - return $accept; - } - $headers = explode(',', $header); - foreach (array_filter($headers) as $value) { - $prefValue = '1.0'; - $value = trim($value); - - $semiPos = strpos($value, ';'); - if ($semiPos !== false) { - $params = explode(';', $value); - $value = trim($params[0]); - foreach ($params as $param) { - $qPos = strpos($param, 'q='); - if ($qPos !== false) { - $prefValue = substr($param, $qPos + 2); - } - } - } - - if (!isset($accept[$prefValue])) { - $accept[$prefValue] = []; - } - if ($prefValue) { - $accept[$prefValue][] = $value; - } - } - krsort($accept); - - return $accept; + return HeaderUtility::parseAccept($header); } /** diff --git a/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php b/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php index 4e01026b8..d5af2a37e 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php +++ b/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php @@ -1,10 +1,10 @@ urldecode($name), 'value' => urldecode($value), diff --git a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php index a028433f3..966b57e9e 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php +++ b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php @@ -27,12 +27,16 @@ use Psr\Http\Message\ServerRequestInterface; use Traversable; use TypeError; +use function Cake\Core\getTypeName; +use function Cake\Core\triggerWarning; /** * Cookie Collection * * Provides an immutable collection of cookies objects. Adding or removing * to a collection returns a *new* collection that you must retain. + * + * @template-implements \IteratorAggregate */ class CookieCollection implements IteratorAggregate, Countable { diff --git a/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php b/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php index 5d6b1065f..ee74d3d59 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php +++ b/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php @@ -16,6 +16,8 @@ */ namespace Cake\Http\Exception; +use function Cake\Core\deprecationWarning; + /** * An exception subclass used by routing and application code to * trigger a redirect. diff --git a/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php b/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php index 2df3b396e..529f602e0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php +++ b/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php @@ -18,6 +18,7 @@ use Cake\Core\InstanceConfigTrait; use Throwable; +use function Cake\Core\pluginSplit; /** * The FlashMessage class provides a way for you to write a flash variable diff --git a/app/vendor/cakephp/cakephp/src/Http/HeaderUtility.php b/app/vendor/cakephp/cakephp/src/Http/HeaderUtility.php new file mode 100644 index 000000000..3242179c1 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Http/HeaderUtility.php @@ -0,0 +1,125 @@ + + */ + protected static function parseLinkItem(string $value): array + { + preg_match('/<(.*)>[; ]?[; ]?(.*)?/i', $value, $matches); + + $url = $matches[1]; + $parsedParams = ['link' => $url]; + + $params = $matches[2]; + if ($params) { + $explodedParams = explode(';', $params); + foreach ($explodedParams as $param) { + $explodedParam = explode('=', $param); + $trimedKey = trim($explodedParam[0]); + $trimedValue = trim($explodedParam[1], '"'); + if ($trimedKey === 'title*') { + // See https://www.rfc-editor.org/rfc/rfc8187#section-3.2.3 + preg_match('/(.*)\'(.*)\'(.*)/i', $trimedValue, $matches); + $trimedValue = [ + 'language' => $matches[2], + 'encoding' => $matches[1], + 'value' => urldecode($matches[3]), + ]; + } + $parsedParams[$trimedKey] = $trimedValue; + } + } + + return $parsedParams; + } + + /** + * Parse the Accept header value into weight => value mapping. + * + * @param string $header The header value to parse + * @return array> + */ + public static function parseAccept(string $header): array + { + $accept = []; + if (!$header) { + return $accept; + } + + $headers = explode(',', $header); + foreach (array_filter($headers) as $value) { + $prefValue = '1.0'; + $value = trim($value); + + $semiPos = strpos($value, ';'); + if ($semiPos !== false) { + $params = explode(';', $value); + $value = trim($params[0]); + foreach ($params as $param) { + $qPos = strpos($param, 'q='); + if ($qPos !== false) { + $prefValue = substr($param, $qPos + 2); + } + } + } + + if (!isset($accept[$prefValue])) { + $accept[$prefValue] = []; + } + if ($prefValue) { + $accept[$prefValue][] = $value; + } + } + krsort($accept); + + return $accept; + } + + /** + * @param string $value The WWW-Authenticate header + * @return array + */ + public static function parseWwwAuthenticate(string $value): array + { + preg_match_all( + '@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', + $value, + $matches, + PREG_SET_ORDER + ); + + $return = []; + foreach ($matches as $match) { + $return[$match[1]] = $match[3] ?? $match[2]; + } + + return $return; + } +} diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php index a350b24f4..a10d7b53e 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php @@ -29,6 +29,8 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\I18n\__d; /** * Provides CSRF protection & validation. diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php index 7bf83d67b..96eec01cb 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php @@ -21,6 +21,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use function Cake\Core\deprecationWarning; /** * Decorate double-pass middleware as PSR-15 middleware. diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php index 709cc6f10..81458e858 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php @@ -18,6 +18,7 @@ use Cake\Core\Configure; use Cake\Http\Exception\BadRequestException; +use Cake\Http\ServerRequest; use Laminas\Diactoros\Response\RedirectResponse; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -39,6 +40,7 @@ class HttpsEnforcerMiddleware implements MiddlewareInterface * - `statusCode` - Status code to use in case of redirect, defaults to 301 - Permanent redirect. * - `headers` - Array of response headers in case of redirect. * - `disableOnDebug` - Whether HTTPS check should be disabled when debug is on. Default `true`. + * - `trustedProxies` - Array of trusted proxies that will be passed to the request. Defaults to `null`. * - 'hsts' - Strict-Transport-Security header for HTTPS response configuration. Defaults to `null`. * If enabled, an array of config options: * @@ -53,6 +55,7 @@ class HttpsEnforcerMiddleware implements MiddlewareInterface 'statusCode' => 301, 'headers' => [], 'disableOnDebug' => true, + 'trustedProxies' => null, 'hsts' => null, ]; @@ -80,6 +83,10 @@ public function __construct(array $config = []) */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { + if ($request instanceof ServerRequest && is_array($this->config['trustedProxies'])) { + $request->setTrustedProxies($this->config['trustedProxies']); + } + if ( $request->getUri()->getScheme() === 'https' || ($this->config['disableOnDebug'] diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php index abba6cd1a..82b2279e7 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php @@ -18,6 +18,7 @@ use ArrayAccess; use Cake\Http\Exception\InvalidCsrfTokenException; +use Cake\Http\ServerRequest; use Cake\Http\Session; use Cake\Utility\Hash; use Cake\Utility\Security; @@ -26,6 +27,7 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; +use function Cake\I18n\__d; /** * Provides CSRF protection via session based tokens. @@ -267,4 +269,24 @@ protected function validateToken(ServerRequestInterface $request, Session $sessi 'CSRF token from either the request body or request headers did not match or is missing.' )); } + + /** + * Replace the token in the provided request. + * + * Replace the token in the session and request attribute. Replacing + * tokens is a good idea during privilege escalation or privilege reduction. + * + * @param \Cake\Http\ServerRequest $request The request to update + * @param string $key The session key/attribute to set. + * @return \Cake\Http\ServerRequest An updated request. + */ + public static function replaceToken(ServerRequest $request, string $key = 'csrfToken'): ServerRequest + { + $middleware = new SessionCsrfProtectionMiddleware(['key' => $key]); + + $token = $middleware->createToken(); + $request->getSession()->write($key, $token); + + return $request->withAttribute($key, $middleware->saltToken($token)); + } } diff --git a/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php b/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php index 1069117c0..6079d8cda 100644 --- a/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php +++ b/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php @@ -17,6 +17,7 @@ namespace Cake\Http; use Cake\Core\App; +use Cake\Core\ContainerInterface; use Cake\Http\Middleware\ClosureDecoratorMiddleware; use Cake\Http\Middleware\DoublePassDecoratorMiddleware; use Closure; @@ -50,13 +51,20 @@ class MiddlewareQueue implements Countable, SeekableIterator */ protected $queue = []; + /** + * @var \Cake\Core\ContainerInterface|null + */ + protected $container; + /** * Constructor * * @param array $middleware The list of middleware to append. + * @param \Cake\Core\ContainerInterface $container Container instance. */ - public function __construct(array $middleware = []) + public function __construct(array $middleware = [], ?ContainerInterface $container = null) { + $this->container = $container; $this->queue = $middleware; } @@ -70,14 +78,20 @@ public function __construct(array $middleware = []) protected function resolve($middleware): MiddlewareInterface { if (is_string($middleware)) { - $className = App::className($middleware, 'Middleware', 'Middleware'); - if ($className === null) { - throw new RuntimeException(sprintf( - 'Middleware "%s" was not found.', - $middleware - )); + if ($this->container && $this->container->has($middleware)) { + $middleware = $this->container->get($middleware); + } else { + $className = App::className($middleware, 'Middleware', 'Middleware'); + if ($className === null) { + throw new RuntimeException( + sprintf( + 'Middleware "%s" was not found.', + $middleware + ) + ); + } + $middleware = new $className(); } - $middleware = new $className(); } if ($middleware instanceof MiddlewareInterface) { diff --git a/app/vendor/cakephp/cakephp/src/Http/Response.php b/app/vendor/cakephp/cakephp/src/Http/Response.php index 3feb4b4b1..d8833deaa 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Response.php +++ b/app/vendor/cakephp/cakephp/src/Http/Response.php @@ -29,6 +29,9 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; use SplFileInfo; +use function Cake\Core\deprecationWarning; +use function Cake\Core\env; +use function Cake\I18n\__d; /** * Responses contain the response text, status and headers of a HTTP response. @@ -1387,9 +1390,9 @@ public function withCookieCollection(CookieCollection $cookieCollection) public function cors(ServerRequest $request): CorsBuilder { $origin = $request->getHeaderLine('Origin'); - $ssl = $request->is('ssl'); + $https = $request->is('https'); - return new CorsBuilder($this, $origin, $ssl); + return new CorsBuilder($this, $origin, $https); } /** diff --git a/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php b/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php index 2dac3d4ca..0cbb23c6f 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php +++ b/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php @@ -232,7 +232,6 @@ protected function setCookie($cookie): bool } if (PHP_VERSION_ID >= 70300) { - /** @psalm-suppress InvalidArgument */ return setcookie($cookie->getName(), $cookie->getScalarValue(), $cookie->getOptions()); } diff --git a/app/vendor/cakephp/cakephp/src/Http/Server.php b/app/vendor/cakephp/cakephp/src/Http/Server.php index fe90d51f0..ea9cf5973 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Server.php +++ b/app/vendor/cakephp/cakephp/src/Http/Server.php @@ -16,6 +16,7 @@ */ namespace Cake\Http; +use Cake\Core\ContainerApplicationInterface; use Cake\Core\HttpApplicationInterface; use Cake\Core\PluginApplicationInterface; use Cake\Event\EventDispatcherInterface; @@ -80,7 +81,15 @@ public function run( $request = $request ?: ServerRequestFactory::fromGlobals(); - $middleware = $this->app->middleware($middlewareQueue ?? new MiddlewareQueue()); + if ($middlewareQueue === null) { + if ($this->app instanceof ContainerApplicationInterface) { + $middlewareQueue = new MiddlewareQueue([], $this->app->getContainer()); + } else { + $middlewareQueue = new MiddlewareQueue(); + } + } + + $middleware = $this->app->middleware($middlewareQueue); if ($this->app instanceof PluginApplicationInterface) { $middleware = $this->app->pluginMiddleware($middleware); } diff --git a/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php b/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php index eaf661177..cd63b5375 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php +++ b/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php @@ -30,6 +30,8 @@ use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; use Psr\Http\Message\UriInterface; +use function Cake\Core\deprecationWarning; +use function Cake\Core\env; /** * A class that helps wrap Request information and particulars about a single request. @@ -127,6 +129,7 @@ class ServerRequest implements ServerRequestInterface 'head' => ['env' => 'REQUEST_METHOD', 'value' => 'HEAD'], 'options' => ['env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'], 'ssl' => ['env' => 'HTTPS', 'options' => [1, 'on']], + 'https' => ['env' => 'HTTPS', 'options' => [1, 'on']], 'ajax' => ['env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'], 'json' => ['accept' => ['application/json'], 'param' => '_ext', 'value' => 'json'], 'xml' => [ @@ -485,6 +488,7 @@ public function __call(string $name, array $params) * this method will return true if the request matches any type. * @param mixed ...$args List of arguments * @return bool Whether the request is the type you are checking. + * @throws \InvalidArgumentException If no detector has been set for the provided type. */ public function is($type, ...$args): bool { @@ -500,7 +504,7 @@ public function is($type, ...$args): bool $type = strtolower($type); if (!isset(static::$_detectors[$type])) { - return false; + throw new InvalidArgumentException("No detector set for type `{$type}`"); } if ($args) { return $this->_is($type, $args); @@ -528,6 +532,9 @@ public function clearDetectorCache(): void */ protected function _is(string $type, array $args): bool { + if ($type === 'ssl') { + deprecationWarning('The `ssl` detector is deprecated. Use `https` instead.'); + } $detect = static::$_detectors[$type]; if (is_callable($detect)) { array_unshift($args, $this); @@ -1792,7 +1799,6 @@ public function withUri(UriInterface $uri, $preserveHost = false) * request-target forms allowed in request messages) * @param string $requestTarget The request target. * @return static - * @psalm-suppress MoreSpecificImplementedParamType */ public function withRequestTarget($requestTarget) { diff --git a/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php b/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php index fe6e4f9f4..836c3c5b0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php +++ b/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php @@ -71,7 +71,6 @@ public static function fromGlobals( $uri->getUri(); } - /** @psalm-suppress NoInterfaceProperties */ $sessionConfig = (array)Configure::read('Session') + [ 'defaults' => 'php', 'cookiePath' => $webroot, @@ -248,14 +247,7 @@ protected static function marshalUriFromSapi(array $server, array $headers): Uri $uri = marshalUriFromSapi($server, $headers); [$base, $webroot] = static::getBase($uri, $server); - // Look in PATH_INFO first, as this is the exact value we need prepared - // by PHP. - $pathInfo = Hash::get($server, 'PATH_INFO'); - if ($pathInfo) { - $uri = $uri->withPath($pathInfo); - } else { - $uri = static::updatePath($base, $uri); - } + $uri = static::updatePath($base, $uri); if (!$uri->getHost()) { $uri = $uri->withHost('localhost'); @@ -283,12 +275,18 @@ protected static function updatePath(string $base, UriInterface $uri): UriInterf if (empty($path) || $path === '/' || $path === '//' || $path === '/index.php') { $path = '/'; } - $endsWithIndex = '/' . (Configure::read('App.webroot') ?: 'webroot') . '/index.php'; - $endsWithLength = strlen($endsWithIndex); - if ( - strlen($path) >= $endsWithLength && - substr($path, -$endsWithLength) === $endsWithIndex - ) { + // Check for $webroot/index.php at the start and end of the path. + $search = ''; + if ($path[0] === '/') { + $search .= '/'; + } + $search .= (Configure::read('App.webroot') ?: 'webroot') . '/index.php'; + if (strpos($path, $search) === 0) { + $path = substr($path, strlen($search)); + } elseif (substr($path, -strlen($search)) === $search) { + $path = '/'; + } + if (!$path) { $path = '/'; } @@ -322,9 +320,9 @@ protected static function getBase(UriInterface $uri, array $server): array // Clean up additional / which cause following code to fail.. $base = preg_replace('#/+#', '/', $base); - $indexPos = strpos($base, '/' . $webroot . '/index.php'); + $indexPos = strpos($base, '/index.php'); if ($indexPos !== false) { - $base = substr($base, 0, $indexPos) . '/' . $webroot; + $base = substr($base, 0, $indexPos); } if ($webroot === basename($base)) { $base = dirname($base); diff --git a/app/vendor/cakephp/cakephp/src/Http/Session.php b/app/vendor/cakephp/cakephp/src/Http/Session.php index d9a88e35e..c3cf9ae07 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Session.php +++ b/app/vendor/cakephp/cakephp/src/Http/Session.php @@ -23,6 +23,7 @@ use InvalidArgumentException; use RuntimeException; use SessionHandlerInterface; +use function Cake\Core\env; /** * This class is a wrapper for the native PHP session functions. It provides @@ -526,7 +527,6 @@ public function write($name, $value = null): void $data = Hash::insert($data, $key, $val); } - /** @psalm-suppress PossiblyNullArgument */ $this->_overwrite($_SESSION, $data); } diff --git a/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php b/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php index 0c5f75b15..d4281d2d0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php +++ b/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php @@ -115,3 +115,10 @@ public function mockClientDelete(string $url, Response $response, array $options Client::addMockResponse('DELETE', $url, $response, $options); } } + +// phpcs:disable +class_alias( + 'Cake\Http\TestSuite\HttpClientTrait', + 'Cake\TestSuite\HttpClientTrait' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/I18n/Date.php b/app/vendor/cakephp/cakephp/src/I18n/Date.php index 3dcc47eb2..9678bfdeb 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Date.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Date.php @@ -18,6 +18,7 @@ use Cake\Chronos\MutableDate; use IntlDateFormatter; +use function Cake\Core\deprecationWarning; /** * Extends the Date class provided by Chronos. diff --git a/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php b/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php index 942ce1a30..dca02329c 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php +++ b/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php @@ -262,7 +262,7 @@ protected function _formatObject($date, $format, ?string $locale): string static::$_formatters[$key] = $formatter; } - return static::$_formatters[$key]->format($date->format('U')); + return static::$_formatters[$key]->format($date); } /** diff --git a/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php b/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php index 4596bb0ea..84d11f1cd 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php +++ b/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php @@ -16,7 +16,7 @@ */ namespace Cake\I18n; -use Cake\Chronos\Date as ChronosDate; +use Cake\Chronos\ChronosDate; use IntlDateFormatter; /** diff --git a/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php b/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php index e3993d9f5..d47e86923 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php +++ b/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php @@ -21,6 +21,7 @@ use Cake\Utility\Inflector; use Locale; use RuntimeException; +use function Cake\Core\pluginSplit; /** * A generic translations package factory that will load translations files @@ -37,6 +38,13 @@ class MessagesFileLoader */ protected $_name; + /** + * The package (domain) plugin + * + * @var string|null + */ + protected $_plugin; + /** * The locale to load for the given package. * @@ -93,6 +101,13 @@ class MessagesFileLoader public function __construct(string $name, string $locale, string $extension = 'po') { $this->_name = $name; + // If space is not added after slash, the character after it remains lowercased + $pluginName = Inflector::camelize(str_replace('/', '/ ', $this->_name)); + if (strpos($this->_name, '.')) { + [$this->_plugin, $this->_name] = pluginSplit($pluginName); + } elseif (Plugin::isLoaded($pluginName)) { + $this->_plugin = $pluginName; + } $this->_locale = $locale; $this->_extension = $extension; } @@ -166,15 +181,17 @@ public function translationsFolders(): array foreach ($localePaths as $path) { foreach ($folders as $folder) { $searchPaths[] = $path . $folder . DIRECTORY_SEPARATOR; + // gettext compatible paths, see https://www.php.net/manual/en/function.gettext.php + $searchPaths[] = $path . $folder . DIRECTORY_SEPARATOR . 'LC_MESSAGES' . DIRECTORY_SEPARATOR; } } - // If space is not added after slash, the character after it remains lowercased - $pluginName = Inflector::camelize(str_replace('/', '/ ', $this->_name)); - if (Plugin::isLoaded($pluginName)) { - $basePath = App::path('locales', $pluginName)[0]; + if ($this->_plugin && Plugin::isLoaded($this->_plugin)) { + $basePath = App::path('locales', $this->_plugin)[0]; foreach ($folders as $folder) { $searchPaths[] = $basePath . $folder . DIRECTORY_SEPARATOR; + // gettext compatible paths, see https://www.php.net/manual/en/function.gettext.php + $searchPaths[] = $basePath . $folder . DIRECTORY_SEPARATOR . 'LC_MESSAGES' . DIRECTORY_SEPARATOR; } } diff --git a/app/vendor/cakephp/cakephp/src/I18n/Number.php b/app/vendor/cakephp/cakephp/src/I18n/Number.php index accd550b0..6c12f715a 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Number.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Number.php @@ -17,6 +17,7 @@ namespace Cake\I18n; use NumberFormatter; +use function Cake\Core\deprecationWarning; /** * Number helper library. @@ -85,7 +86,7 @@ class Number * * - `locale`: The locale name to use for formatting the number, e.g. fr_FR * - * @param string|float $value A floating point number. + * @param string|float|int $value A floating point number. * @param int $precision The precision of the returned number. * @param array $options Additional options * @return string Formatted float. @@ -101,7 +102,7 @@ public static function precision($value, int $precision = 3, array $options = [] /** * Returns a formatted-for-humans file size. * - * @param string|int $size Size in bytes + * @param string|float|int $size Size in bytes * @return string Human readable size * @link https://book.cakephp.org/4/en/core-libraries/number.html#interacting-with-human-readable-values */ @@ -131,7 +132,7 @@ public static function toReadableSize($size): string * - `multiply`: Multiply the input value by 100 for decimal percentages. * - `locale`: The locale name to use for formatting the number, e.g. fr_FR * - * @param string|float $value A floating point number + * @param string|float|int $value A floating point number * @param int $precision The precision of the returned number * @param array $options Options * @return string Percentage string @@ -230,6 +231,8 @@ public static function formatDelta($value, array $options = []): string * - `zero` - The text to use for zero values, can be a string or a number. e.g. 0, 'Free!' * - `places` - Number of decimal places to use. e.g. 2 * - `precision` - Maximum Number of decimal places to use, e.g. 2 + * - `roundingMode` - Rounding mode to use. e.g. NumberFormatter::ROUND_HALF_UP. + * When not set locale default will be used * - `pattern` - An ICU number pattern to use for formatting the number. e.g #,##0.00 * - `useIntlCode` - Whether to replace the currency symbol with the international * currency code. @@ -364,6 +367,8 @@ public static function setDefaultCurrencyFormat($currencyFormat = null): void * numbers representing money or a NumberFormatter constant. * - `places` - Number of decimal places to use. e.g. 2 * - `precision` - Maximum Number of decimal places to use, e.g. 2 + * - `roundingMode` - Rounding mode to use. e.g. NumberFormatter::ROUND_HALF_UP. + * When not set locale default will be used * - `pattern` - An ICU number pattern to use for formatting the number. e.g #,##0.00 * - `useIntlCode` - Whether to replace the currency symbol with the international * currency code. @@ -405,6 +410,7 @@ public static function formatter(array $options = []): NumberFormatter $options = array_intersect_key($options, [ 'places' => null, 'precision' => null, + 'roundingMode' => null, 'pattern' => null, 'useIntlCode' => null, ]); @@ -451,6 +457,10 @@ protected static function _setAttributes(NumberFormatter $formatter, array $opti $formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $options['precision']); } + if (isset($options['roundingMode'])) { + $formatter->setAttribute(NumberFormatter::ROUNDING_MODE, $options['roundingMode']); + } + if (!empty($options['pattern'])) { $formatter->setPattern($options['pattern']); } diff --git a/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php b/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php index a3b195923..e4aa46270 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php @@ -94,7 +94,6 @@ public function parse(string $resource): array } elseif (substr($line, 0, 7) === 'msgid "') { // We start a new msg so save previous $this->_addMessage($messages, $item); - /** @psalm-suppress InvalidArrayOffset */ $item['ids']['singular'] = substr($line, 7, -1); $stage = ['ids', 'singular']; } elseif (substr($line, 0, 8) === 'msgstr "') { @@ -124,7 +123,6 @@ public function parse(string $resource): array break; } } elseif (substr($line, 0, 14) === 'msgid_plural "') { - /** @psalm-suppress InvalidArrayOffset */ $item['ids']['plural'] = substr($line, 14, -1); $stage = ['ids', 'plural']; } elseif (substr($line, 0, 7) === 'msgstr[') { diff --git a/app/vendor/cakephp/cakephp/src/I18n/Time.php b/app/vendor/cakephp/cakephp/src/I18n/Time.php index 9528e9de3..9209418cc 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Time.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Time.php @@ -20,6 +20,7 @@ use DateTimeInterface; use DateTimeZone; use IntlDateFormatter; +use function Cake\Core\deprecationWarning; /** * Extends the built-in DateTime class to provide handy methods and locale-aware diff --git a/app/vendor/cakephp/cakephp/src/I18n/functions.php b/app/vendor/cakephp/cakephp/src/I18n/functions.php index 45f17250f..3295049ad 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/functions.php +++ b/app/vendor/cakephp/cakephp/src/I18n/functions.php @@ -14,240 +14,221 @@ * @since 3.0.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ +namespace Cake\I18n; -use Cake\I18n\I18n; - +// phpcs:disable PSR1.Files.SideEffects // Backwards compatibility alias for custom translation messages loaders which return a Package instance. -// phpcs:disable if (!class_exists('Aura\Intl\Package')) { class_alias('Cake\I18n\Package', 'Aura\Intl\Package'); } -// phpcs:enable - -if (!function_exists('__')) { - /** - * Returns a translated string if one is found; Otherwise, the submitted message. - * - * @param string $singular Text to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string The translated text. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__ - */ - function __(string $singular, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate($singular, $args); + +/** + * Returns a translated string if one is found; Otherwise, the submitted message. + * + * @param string $singular Text to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string The translated text. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__ + */ +function __(string $singular, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate($singular, $args); } -if (!function_exists('__n')) { - /** - * Returns correct plural form of message identified by $singular and $plural for count $count. - * Some languages have more than one form for plural messages dependent on the count. - * - * @param string $singular Singular text to translate. - * @param string $plural Plural text. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__n - */ - function __n(string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate( - $plural, - ['_count' => $count, '_singular' => $singular] + $args - ); +/** + * Returns correct plural form of message identified by $singular and $plural for count $count. + * Some languages have more than one form for plural messages dependent on the count. + * + * @param string $singular Singular text to translate. + * @param string $plural Plural text. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__n + */ +function __n(string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate( + $plural, + ['_count' => $count, '_singular' => $singular] + $args + ); } -if (!function_exists('__d')) { - /** - * Allows you to override the current domain for a single message lookup. - * - * @param string $domain Domain. - * @param string $msg String to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__d - */ - function __d(string $domain, string $msg, ...$args): string - { - if (!$msg) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate($msg, $args); +/** + * Allows you to override the current domain for a single message lookup. + * + * @param string $domain Domain. + * @param string $msg String to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__d + */ +function __d(string $domain, string $msg, ...$args): string +{ + if (!$msg) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate($msg, $args); } -if (!function_exists('__dn')) { - /** - * Allows you to override the current domain for a single plural message lookup. - * Returns correct plural form of message identified by $singular and $plural for count $count - * from domain $domain. - * - * @param string $domain Domain. - * @param string $singular Singular string to translate. - * @param string $plural Plural. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dn - */ - function __dn(string $domain, string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate( - $plural, - ['_count' => $count, '_singular' => $singular] + $args - ); +/** + * Allows you to override the current domain for a single plural message lookup. + * Returns correct plural form of message identified by $singular and $plural for count $count + * from domain $domain. + * + * @param string $domain Domain. + * @param string $singular Singular string to translate. + * @param string $plural Plural. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dn + */ +function __dn(string $domain, string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate( + $plural, + ['_count' => $count, '_singular' => $singular] + $args + ); } -if (!function_exists('__x')) { - /** - * Returns a translated string if one is found; Otherwise, the submitted message. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $context Context of the text. - * @param string $singular Text to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__x - */ - function __x(string $context, string $singular, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate($singular, ['_context' => $context] + $args); +/** + * Returns a translated string if one is found; Otherwise, the submitted message. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $context Context of the text. + * @param string $singular Text to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__x + */ +function __x(string $context, string $singular, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate($singular, ['_context' => $context] + $args); } -if (!function_exists('__xn')) { - /** - * Returns correct plural form of message identified by $singular and $plural for count $count. - * Some languages have more than one form for plural messages dependent on the count. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $context Context of the text. - * @param string $singular Singular text to translate. - * @param string $plural Plural text. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__xn - */ - function __xn(string $context, string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate( - $plural, - ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args - ); +/** + * Returns correct plural form of message identified by $singular and $plural for count $count. + * Some languages have more than one form for plural messages dependent on the count. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $context Context of the text. + * @param string $singular Singular text to translate. + * @param string $plural Plural text. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__xn + */ +function __xn(string $context, string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate( + $plural, + ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args + ); } -if (!function_exists('__dx')) { - /** - * Allows you to override the current domain for a single message lookup. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $domain Domain. - * @param string $context Context of the text. - * @param string $msg String to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dx - */ - function __dx(string $domain, string $context, string $msg, ...$args): string - { - if (!$msg) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate( - $msg, - ['_context' => $context] + $args - ); +/** + * Allows you to override the current domain for a single message lookup. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $domain Domain. + * @param string $context Context of the text. + * @param string $msg String to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dx + */ +function __dx(string $domain, string $context, string $msg, ...$args): string +{ + if (!$msg) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate( + $msg, + ['_context' => $context] + $args + ); } -if (!function_exists('__dxn')) { - /** - * Returns correct plural form of message identified by $singular and $plural for count $count. - * Allows you to override the current domain for a single message lookup. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $domain Domain. - * @param string $context Context of the text. - * @param string $singular Singular text to translate. - * @param string $plural Plural text. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dxn - */ - function __dxn(string $domain, string $context, string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate( - $plural, - ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args - ); +/** + * Returns correct plural form of message identified by $singular and $plural for count $count. + * Allows you to override the current domain for a single message lookup. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $domain Domain. + * @param string $context Context of the text. + * @param string $singular Singular text to translate. + * @param string $plural Plural text. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dxn + */ +function __dxn(string $domain, string $context, string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate( + $plural, + ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args + ); +} + +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; } diff --git a/app/vendor/cakephp/cakephp/src/I18n/functions_global.php b/app/vendor/cakephp/cakephp/src/I18n/functions_global.php new file mode 100644 index 000000000..94e48d381 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/I18n/functions_global.php @@ -0,0 +1,174 @@ + @@ -54,6 +55,7 @@ class FileLog extends BaseLog 'rotate' => 10, 'size' => 10485760, // 10MB 'mask' => null, + 'dirMask' => 0770, 'formatter' => [ 'className' => DefaultFormatter::class, ], @@ -90,8 +92,8 @@ public function __construct(array $config = []) parent::__construct($config); $this->_path = $this->getConfig('path', sys_get_temp_dir() . DIRECTORY_SEPARATOR); - if (Configure::read('debug') && !is_dir($this->_path)) { - mkdir($this->_path, 0775, true); + if (!is_dir($this->_path)) { + mkdir($this->_path, $this->_config['dirMask'], true); } if (!empty($this->_config['file'])) { diff --git a/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php b/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php index 1e48d0d52..5f8c6d342 100644 --- a/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php +++ b/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php @@ -18,6 +18,7 @@ use Cake\Log\Formatter\DefaultFormatter; use Cake\Log\Formatter\LegacySyslogFormatter; +use function Cake\Core\deprecationWarning; /** * Syslog stream for Logging. Writes logs to the system logger diff --git a/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php b/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php index 113f67002..535ade03f 100644 --- a/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php +++ b/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php @@ -20,6 +20,7 @@ use Cake\Core\ObjectRegistry; use Psr\Log\LoggerInterface; use RuntimeException; +use function Cake\Core\getTypeName; /** * Registry of loaded log engines @@ -79,7 +80,6 @@ protected function _create($class, string $alias, array $config): LoggerInterfac } if (!isset($instance)) { - /** @psalm-suppress UndefinedClass */ $instance = new $class($config); } diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php b/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php index ce1b87fab..1cd89c23f 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php @@ -24,6 +24,7 @@ use Cake\ORM\Locator\LocatorAwareTrait; use Cake\View\ViewBuilder; use InvalidArgumentException; +use function Cake\Core\deprecationWarning; /** * Mailer base class. diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Message.php b/app/vendor/cakephp/cakephp/src/Mailer/Message.php index 9b51be0e1..78ae98a62 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Message.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Message.php @@ -28,6 +28,7 @@ use Psr\Http\Message\UploadedFileInterface; use Serializable; use SimpleXMLElement; +use function Cake\Core\env; /** * Email message class. @@ -301,6 +302,18 @@ class Message implements JsonSerializable, Serializable */ protected $emailPattern = self::EMAIL_PATTERN; + /** + * Properties that could be serialized + * + * @var array + */ + protected $serializableProperties = [ + 'to', 'from', 'sender', 'replyTo', 'cc', 'bcc', 'subject', + 'returnPath', 'readReceipt', 'emailFormat', 'emailPattern', 'domain', + 'attachments', 'messageId', 'headers', 'appCharset', 'charset', 'headerCharset', + 'textMessage', 'htmlMessage', + ]; + /** * Constructor * @@ -999,8 +1012,8 @@ protected function formatAddress(array $address): array $return[] = $email; } else { $encoded = $this->encodeForHeader($alias); - if ($encoded === $alias && preg_match('/[^a-z0-9 ]/i', $encoded)) { - $encoded = '"' . str_replace('"', '\"', $encoded) . '"'; + if (preg_match('/[^a-z0-9+\-\\=? ]/i', $encoded)) { + $encoded = '"' . addcslashes($encoded, '"\\') . '"'; } $return[] = sprintf('%s <%s>', $encoded, $email); } @@ -1151,7 +1164,7 @@ public function getDomain(): string * ``` * * The `contentId` key allows you to specify an inline attachment. In your email text, you - * can use `` to display the image inline. + * can use `` to display the image inline. * * The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve * attachment compatibility with outlook email clients. @@ -1849,15 +1862,8 @@ public function getContentTypeCharset(): string */ public function jsonSerialize(): array { - $properties = [ - 'to', 'from', 'sender', 'replyTo', 'cc', 'bcc', 'subject', - 'returnPath', 'readReceipt', 'emailFormat', 'emailPattern', 'domain', - 'attachments', 'messageId', 'headers', 'appCharset', 'charset', 'headerCharset', - 'textMessage', 'htmlMessage', - ]; - $array = []; - foreach ($properties as $property) { + foreach ($this->serializableProperties as $property) { $array[$property] = $this->{$property}; } diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php b/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php index 2c394309f..32cef1f86 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php @@ -18,6 +18,7 @@ use Cake\View\View; use Cake\View\ViewVarsTrait; +use function Cake\Core\pluginSplit; /** * Class for rendering email message. diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php b/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php index 0e6409eed..428316b47 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php @@ -23,6 +23,7 @@ use Cake\Network\Socket; use Exception; use RuntimeException; +use function Cake\Core\env; /** * Send mail using SMTP protocol diff --git a/app/vendor/cakephp/cakephp/src/Network/Socket.php b/app/vendor/cakephp/cakephp/src/Network/Socket.php index e94d8eab9..bfcdbc14f 100644 --- a/app/vendor/cakephp/cakephp/src/Network/Socket.php +++ b/app/vendor/cakephp/cakephp/src/Network/Socket.php @@ -23,6 +23,7 @@ use Composer\CaBundle\CaBundle; use Exception; use InvalidArgumentException; +use function Cake\Core\deprecationWarning; /** * CakePHP network socket connection class. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association.php b/app/vendor/cakephp/cakephp/src/ORM/Association.php index 9621dd2c4..8601283b7 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association.php @@ -29,6 +29,8 @@ use Closure; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\pluginSplit; /** * An Association is a relationship established between two tables and is used diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php index 1950b2568..3072073a5 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php @@ -24,12 +24,16 @@ use Cake\Utility\Inflector; use Closure; use RuntimeException; +use function Cake\Core\pluginSplit; /** * Represents an 1 - N relationship where the source side of the relation is * related to only one record in the target table. * * An example of a BelongsTo association would be Article belongs to Author. + * + * @template T of \Cake\ORM\Table + * @mixin T */ class BelongsTo extends Association { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php index f43402258..71b26e4a0 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php @@ -37,6 +37,9 @@ * * An example of a BelongsToMany association would be Article belongs to many Tags. * In this example 'Article' is the source table and 'Tags' is the target table. + * + * @template T of \Cake\ORM\Table + * @mixin T */ class BelongsToMany extends Association { @@ -1206,7 +1209,7 @@ function () use ($sourceEntity, $targetEntities, $primaryValue, $options) { // Create a subquery join to ensure we get // the correct entity passed to callbacks. - $existing = $junction->query() + $existing = $junction->selectQuery() ->from([$junctionQueryAlias => $matches]) ->innerJoin( [$junction->getAlias() => $junction->getTable()], diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/HasMany.php b/app/vendor/cakephp/cakephp/src/ORM/Association/HasMany.php index 9dbeac72b..5d95621da 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/HasMany.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/HasMany.php @@ -33,6 +33,9 @@ * will have one or multiple records per each one in the source side. * * An example of a HasMany association would be Author has many Articles. + * + * @template T of \Cake\ORM\Table + * @mixin T */ class HasMany extends Association { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php b/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php index b48ea7213..ff239477d 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php @@ -22,12 +22,16 @@ use Cake\ORM\Table; use Cake\Utility\Inflector; use Closure; +use function Cake\Core\pluginSplit; /** * Represents an 1 - 1 relationship where the source side of the relation is * related to only one record in the target table and vice versa. * * An example of a HasOne association would be User has one Profile. + * + * @template T of \Cake\ORM\Table + * @mixin T */ class HasOne extends Association { diff --git a/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php b/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php index 9e9e9c0d1..9f213145a 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php +++ b/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php @@ -23,12 +23,16 @@ use InvalidArgumentException; use IteratorAggregate; use Traversable; +use function Cake\Core\namespaceSplit; +use function Cake\Core\pluginSplit; /** * A container/collection for association classes. * * Contains methods for managing associations, and * ordering operations around saving and deleting. + * + * @template-implements \IteratorAggregate */ class AssociationCollection implements IteratorAggregate { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior.php index 31ab1f295..485770880 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior.php @@ -21,6 +21,7 @@ use Cake\Event\EventListenerInterface; use ReflectionClass; use ReflectionMethod; +use function Cake\Core\deprecationWarning; /** * Base class for behaviors. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php index 3284c3dc1..2408090b1 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php @@ -27,6 +27,7 @@ use Cake\ORM\Query; use Cake\ORM\Table; use Cake\Utility\Hash; +use function Cake\Core\pluginSplit; /** * This class provides a way to translate dynamic data by keeping translations @@ -266,7 +267,6 @@ function ($c, &$field) use ($fields, $alias, $mainTableAlias, $mainTableFields, return $c; } - /** @psalm-suppress ParadoxicalCondition */ if (in_array($field, $fields, true)) { $joinRequired = true; $field = "$alias.$field"; @@ -323,7 +323,6 @@ function ($expression) use ($fields, $alias, $mainTableAlias, $mainTableFields, return; } - /** @psalm-suppress ParadoxicalCondition */ if (in_array($field, $mainTableFields, true)) { $expression->setField("$mainTableAlias.$field"); } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php index dc0df6671..576ea8909 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php @@ -25,6 +25,7 @@ use Cake\ORM\Query; use Cake\ORM\Table; use Cake\Utility\Inflector; +use function Cake\Core\namespaceSplit; /** * This behavior provides a way to translate dynamic data by keeping translations diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php index b009d0d52..493bea37d 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php @@ -18,6 +18,7 @@ use Cake\Collection\CollectionInterface; use Cake\Database\Expression\IdentifierExpression; +use Cake\Database\Expression\QueryExpression; use Cake\Datasource\EntityInterface; use Cake\Datasource\Exception\RecordNotFoundException; use Cake\Event\EventInterface; @@ -227,20 +228,24 @@ public function beforeDelete(EventInterface $event, EntityInterface $entity) $diff = $right - $left + 1; if ($diff > 2) { - $query = $this->_scope($this->_table->query()) - ->where(function ($exp) use ($config, $left, $right) { - /** @var \Cake\Database\Expression\QueryExpression $exp */ - return $exp - ->gte($config['leftField'], $left + 1) - ->lte($config['leftField'], $right - 1); - }); if ($this->getConfig('cascadeCallbacks')) { + $query = $this->_scope($this->_table->selectQuery()) + ->where(function (QueryExpression $exp) use ($config, $left, $right) { + return $exp + ->gte($config['leftField'], $left + 1) + ->lte($config['leftField'], $right - 1); + }); $entities = $query->toArray(); foreach ($entities as $entityToDelete) { $this->_table->delete($entityToDelete, ['atomic' => false]); } } else { - $query->delete(); + $query = $this->_scope($this->_table->deleteQuery()) + ->where(function (QueryExpression $exp) use ($config, $left, $right) { + return $exp + ->gte($config['leftField'], $left + 1) + ->lte($config['leftField'], $right - 1); + }); $statement = $query->execute(); $statement->closeCursor(); } @@ -848,7 +853,7 @@ protected function _recoverTree(int $lftRght = 1, $parentId = null, $level = 0): $primaryKey = $this->_getPrimaryKey(); $order = $config['recoverOrder'] ?: $primaryKey; - $nodes = $this->_scope($this->_table->query()) + $nodes = $this->_scope($this->_table->selectQuery()) ->select($primaryKey) ->where([$parent . ' IS' => $parentId]) ->order($order) @@ -911,7 +916,7 @@ protected function _sync(int $shift, string $dir, string $conditions, bool $mark $config = $this->_config; foreach ([$config['leftField'], $config['rightField']] as $field) { - $query = $this->_scope($this->_table->query()); + $query = $this->_scope($this->_table->updateQuery()); $exp = $query->newExpr(); $movement = clone $exp; @@ -925,10 +930,7 @@ protected function _sync(int $shift, string $dir, string $conditions, bool $mark $where = clone $exp; $where->add($field)->add($conditions)->setConjunction(''); - $query->update() - ->set($exp->eq($field, $movement)) - ->where($where); - + $query->set($exp->eq($field, $movement))->where($where); $query->execute()->closeCursor(); } } diff --git a/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php b/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php index e4b76e1c3..fc06b3118 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php +++ b/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php @@ -203,6 +203,49 @@ protected function _getMethods(Behavior $instance, string $class, string $alias) return compact('methods', 'finders'); } + /** + * Set an object directly into the registry by name. + * + * @param string $name The name of the object to set in the registry. + * @param \Cake\ORM\Behavior $object instance to store in the registry + * @return $this + */ + public function set(string $name, object $object) + { + parent::set($name, $object); + + $methods = $this->_getMethods($object, get_class($object), $name); + $this->_methodMap += $methods['methods']; + $this->_finderMap += $methods['finders']; + + return $this; + } + + /** + * Remove an object from the registry. + * + * If this registry has an event manager, the object will be detached from any events as well. + * + * @param string $name The name of the object to remove from the registry. + * @return $this + */ + public function unload(string $name) + { + $instance = $this->get($name); + $result = parent::unload($name); + + $methods = array_change_key_case($instance->implementedMethods()); + foreach (array_keys($methods) as $method) { + unset($this->_methodMap[$method]); + } + $finders = array_change_key_case($instance->implementedFinders()); + foreach (array_keys($finders) as $finder) { + unset($this->_finderMap[$finder]); + } + + return $result; + } + /** * Check if any loaded behavior implements a method. * diff --git a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php index 1778c32de..d4fa10a25 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php +++ b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php @@ -630,7 +630,7 @@ public function loadExternal(Query $query, StatementInterface $statement): State return $statement; } - $driver = $query->getConnection()->getDriver(); + $driver = $query->getConnection()->getDriver($query->getConnectionRole()); [$collected, $statement] = $this->_collectKeys($external, $query, $statement); // No records found, skip trying to attach associations. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php b/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php index 67a875201..3fefe3f40 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php @@ -25,6 +25,7 @@ use Cake\ORM\Table; use Cake\Utility\Inflector; use RuntimeException; +use function Cake\Core\pluginSplit; /** * Provides a default registry/factory for Table objects. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php b/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php index 7511aafa4..2caa7e573 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php @@ -26,6 +26,8 @@ use Cake\Utility\Hash; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; /** * Contains logic to convert array data into entities. @@ -659,7 +661,6 @@ public function merge(EntityInterface $entity, array $data, array $options = []) * @param array $options List of options. * @return array<\Cake\Datasource\EntityInterface> * @see \Cake\ORM\Entity::$_accessible - * @psalm-suppress NullArrayOffset */ public function mergeMany(iterable $entities, array $data, array $options = []): array { @@ -755,7 +756,6 @@ protected function _mergeAssociation($original, Association $assoc, $value, arra $types = [Association::ONE_TO_ONE, Association::MANY_TO_ONE]; $type = $assoc->type(); if (in_array($type, $types, true)) { - /** @psalm-suppress PossiblyInvalidArgument, ArgumentTypeCoercion */ return $marshaller->merge($original, $value, $options); } if ($type === Association::MANY_TO_MANY) { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query.php b/app/vendor/cakephp/cakephp/src/ORM/Query.php index 7ba368007..3f40d5b6f 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Query.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Query.php @@ -31,6 +31,7 @@ use JsonSerializable; use RuntimeException; use Traversable; +use function Cake\Core\deprecationWarning; /** * Extends the base Query class to provide new methods related to association @@ -51,28 +52,28 @@ * @method \Cake\Collection\CollectionInterface map(callable $c) Modifies each of the results using the callable * @method mixed reduce(callable $c, $zero = null) Folds all the results into a single value using the callable. * @method \Cake\Collection\CollectionInterface extract($field) Extracts a single column from each row - * @method mixed max($field) Returns the maximum value for a single column in all the results. - * @method mixed min($field) Returns the minimum value for a single column in all the results. + * @method mixed max($field, $sort = \SORT_NUMERIC) Returns the maximum value for a single column in all the results. + * @method mixed min($field, $sort = \SORT_NUMERIC) Returns the minimum value for a single column in all the results. * @method \Cake\Collection\CollectionInterface groupBy(callable|string $field) In-memory group all results by the value of a column. * @method \Cake\Collection\CollectionInterface indexBy(callable|string $callback) Returns the results indexed by the value of a column. * @method \Cake\Collection\CollectionInterface countBy(callable|string $field) Returns the number of unique values for a column - * @method float sumOf(callable|string $field) Returns the sum of all values for a single column + * @method int|float sumOf($field = null) Returns the sum of all values for a single column * @method \Cake\Collection\CollectionInterface shuffle() In-memory randomize the order the results are returned * @method \Cake\Collection\CollectionInterface sample(int $size = 10) In-memory shuffle the results and return a subset of them. * @method \Cake\Collection\CollectionInterface take(int $size = 1, int $from = 0) In-memory limit and offset for the query results. * @method \Cake\Collection\CollectionInterface skip(int $howMany) Skips some rows from the start of the query result. * @method mixed last() Return the last row of the query result - * @method \Cake\Collection\CollectionInterface append(array|\Traversable $items) Appends more rows to the result of the query. + * @method \Cake\Collection\CollectionInterface append(mixed $items) Appends more rows to the result of the query. * @method \Cake\Collection\CollectionInterface combine($k, $v, $g = null) Returns the values of the column $v index by column $k, * and grouped by $g. * @method \Cake\Collection\CollectionInterface nest($k, $p, $n = 'children') Creates a tree structure by nesting the values of column $p into that * with the same value for $k using $n as the nesting key. * @method array toArray() Returns a key-value array with the results of this query. * @method array toList() Returns a numerically indexed array with the results of this query. - * @method \Cake\Collection\CollectionInterface stopWhen(callable $c) Returns each row until the callable returns true. - * @method \Cake\Collection\CollectionInterface zip(array|\Traversable $c) Returns the first result of both the query and $c in an array, + * @method \Cake\Collection\CollectionInterface stopWhen(callable|array $c) Returns each row until the callable returns true. + * @method \Cake\Collection\CollectionInterface zip(iterable $c) Returns the first result of both the query and $c in an array, * then the second results and so on. - * @method \Cake\Collection\CollectionInterface zipWith($collections, callable $callable) Returns each of the results out of calling $c + * @method \Cake\Collection\CollectionInterface zipWith(iterable $collections, callable $callable) Returns each of the results out of calling $c * with the first rows of the query and each of the items, then the second rows and so on. * @method \Cake\Collection\CollectionInterface chunk(int $size) Groups the results in arrays of $size rows each. * @method bool isEmpty() Returns true if this query found no results. @@ -178,7 +179,7 @@ class Query extends DatabaseQuery implements JsonSerializable, QueryInterface public function __construct(Connection $connection, Table $table) { parent::__construct($connection); - $this->repository($table); + $this->setRepository($table); if ($this->_repository !== null) { $this->addDefaultTypes($this->_repository); @@ -242,6 +243,24 @@ public function select($fields = [], bool $overwrite = false) return parent::select($fields, $overwrite); } + /** + * Behaves the exact same as `select()` except adds the field to the list of fields selected and + * does not disable auto-selecting fields for Associations. + * + * Use this instead of calling `select()` then `enableAutoFields()` to re-enable auto-fields. + * + * @param \Cake\Database\ExpressionInterface|\Cake\ORM\Table|\Cake\ORM\Association|callable|array|string $fields Fields + * to be added to the list. + * @return $this + */ + public function selectAlso($fields) + { + $this->select($fields); + $this->_autoFields = true; + + return $this; + } + /** * All the fields associated with the passed table except the excluded * fields will be added to the select clause of the query. Passed excluded fields should not be aliased. @@ -977,8 +996,8 @@ protected function _performCount(): int ->disableAutoFields() ->execute(); } else { - $statement = $this->getConnection()->newQuery() - ->select($count) + $statement = $this->getConnection() + ->selectQuery($count) ->from(['count_source' => $query]) ->execute(); } @@ -1440,4 +1459,19 @@ protected function _decorateResults(Traversable $result): ResultSetInterface return $result; } + + /** + * Helper for ORM\Query exceptions + * + * @param string $method The method that is invalid. + * @param string $message An additional message. + * @return void + * @internal + */ + protected function _deprecatedMethod($method, $message = '') + { + $class = static::class; + $text = "As of 4.5.0 calling {$method}() on {$class} is deprecated. " . $message; + deprecationWarning($text); + } } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/DeleteQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/DeleteQuery.php new file mode 100644 index 000000000..40470210e --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/DeleteQuery.php @@ -0,0 +1,337 @@ +_type === 'delete' && empty($this->_parts['from'])) { + $repository = $this->getRepository(); + $this->from([$repository->getAlias() => $repository->getTable()]); + } + + return parent::sql($binder); + } + + /** + * @inheritDoc + */ + public function delete(?string $table = null) + { + $this->_deprecatedMethod('delete()', 'Remove this method call.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function cache($key, $config = 'default') + { + $this->_deprecatedMethod('cache()', 'Use execute() instead.'); + + return parent::cache($key, $config); + } + + /** + * @inheritDoc + */ + public function all(): ResultSetInterface + { + $this->_deprecatedMethod('all()', 'Use execute() instead.'); + + return parent::all(); + } + + /** + * @inheritDoc + */ + public function select($fields = [], bool $overwrite = false) + { + $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.'); + + return parent::select($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function distinct($on = [], $overwrite = false) + { + $this->_deprecatedMethod('distinct()'); + + return parent::distinct($on, $overwrite); + } + + /** + * @inheritDoc + */ + public function modifier($modifiers, $overwrite = false) + { + $this->_deprecatedMethod('modifier()'); + + return parent::modifier($modifiers, $overwrite); + } + + /** + * @inheritDoc + */ + public function join($tables, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('join()'); + + return parent::join($tables, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function removeJoin(string $name) + { + $this->_deprecatedMethod('removeJoin()'); + + return parent::removeJoin($name); + } + + /** + * @inheritDoc + */ + public function leftJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('leftJoin()'); + + return parent::leftJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function rightJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('rightJoin()'); + + return parent::rightJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function leftJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('leftJoinWith()'); + + return parent::leftJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function innerJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('innerJoin()'); + + return parent::innerJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function innerJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('innerJoinWith()'); + + return parent::innerJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function group($fields, $overwrite = false) + { + $this->_deprecatedMethod('group()'); + + return parent::group($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function having($conditions = null, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('having()'); + + return parent::having($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function andHaving($conditions, $types = []) + { + $this->_deprecatedMethod('andHaving()'); + + return parent::andHaving($conditions, $types); + } + + /** + * @inheritDoc + */ + public function page(int $num, ?int $limit = null) + { + $this->_deprecatedMethod('page()'); + + return parent::page($num, $limit); + } + + /** + * @inheritDoc + */ + public function union($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::union($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function unionAll($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::unionAll($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function insert(array $columns, array $types = []) + { + $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.'); + + return parent::insert($columns, $types); + } + + /** + * @inheritDoc + */ + public function into(string $table) + { + $this->_deprecatedMethod('into()', 'Use from() instead.'); + + return parent::into($table); + } + + /** + * @inheritDoc + */ + public function values($data) + { + $this->_deprecatedMethod('values()'); + + return parent::values($data); + } + + /** + * @inheritDoc + */ + public function update($table = null) + { + $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.'); + + return parent::update($table); + } + + /** + * @inheritDoc + */ + public function set($key, $value = null, $types = []) + { + $this->_deprecatedMethod('set()'); + + return parent::set($key, $value, $types); + } + + /** + * @inheritDoc + */ + public function matching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('matching()'); + + return parent::matching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function notMatching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('notMatching()'); + + return parent::notMatching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function contain($associations, $override = false) + { + $this->_deprecatedMethod('contain()'); + + return parent::contain($associations, $override); + } + + /** + * @inheritDoc + */ + public function getContain(): array + { + $this->_deprecatedMethod('getContain()'); + + return parent::getContain(); + } + + /** + * @inheritDoc + */ + public function find(string $finder, array $options = []) + { + $this->_deprecatedMethod('find()'); + + return parent::find($finder, $options); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/InsertQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/InsertQuery.php new file mode 100644 index 000000000..6c3462f97 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/InsertQuery.php @@ -0,0 +1,413 @@ +_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function cache($key, $config = 'default') + { + $this->_deprecatedMethod('cache()', 'Use execute() instead.'); + + return parent::cache($key, $config); + } + + /** + * @inheritDoc + */ + public function all(): ResultSetInterface + { + $this->_deprecatedMethod('all()', 'Use execute() instead.'); + + return parent::all(); + } + + /** + * @inheritDoc + */ + public function select($fields = [], bool $overwrite = false) + { + $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.'); + + return parent::select($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function distinct($on = [], $overwrite = false) + { + $this->_deprecatedMethod('distinct()'); + + return parent::distinct($on, $overwrite); + } + + /** + * @inheritDoc + */ + public function modifier($modifiers, $overwrite = false) + { + $this->_deprecatedMethod('modifier()'); + + return parent::modifier($modifiers, $overwrite); + } + + /** + * @inheritDoc + */ + public function join($tables, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('join()'); + + return parent::join($tables, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function removeJoin(string $name) + { + $this->_deprecatedMethod('removeJoin()'); + + return parent::removeJoin($name); + } + + /** + * @inheritDoc + */ + public function leftJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('leftJoin()'); + + return parent::leftJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function rightJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('rightJoin()'); + + return parent::rightJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function leftJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('leftJoinWith()'); + + return parent::leftJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function innerJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('innerJoin()'); + + return parent::innerJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function innerJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('innerJoinWith()'); + + return parent::innerJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function group($fields, $overwrite = false) + { + $this->_deprecatedMethod('group()'); + + return parent::group($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function having($conditions = null, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('having()'); + + return parent::having($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function andHaving($conditions, $types = []) + { + $this->_deprecatedMethod('andHaving()'); + + return parent::andHaving($conditions, $types); + } + + /** + * @inheritDoc + */ + public function page(int $num, ?int $limit = null) + { + $this->_deprecatedMethod('page()'); + + return parent::page($num, $limit); + } + + /** + * @inheritDoc + */ + public function offset($offset) + { + $this->_deprecatedMethod('offset()'); + + return parent::offset($offset); + } + + /** + * @inheritDoc + */ + public function union($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::union($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function unionAll($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::unionAll($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function from($tables = [], $overwrite = false) + { + $this->_deprecatedMethod('from()', 'Use into() instead.'); + + return parent::from($tables, $overwrite); + } + + /** + * @inheritDoc + */ + public function update($table = null) + { + $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.'); + + return parent::update($table); + } + + /** + * @inheritDoc + */ + public function set($key, $value = null, $types = []) + { + $this->_deprecatedMethod('set()'); + + return parent::set($key, $value, $types); + } + + /** + * @inheritDoc + */ + public function matching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('matching()'); + + return parent::matching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function notMatching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('notMatching()'); + + return parent::notMatching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function contain($associations, $override = false) + { + $this->_deprecatedMethod('contain()'); + + return parent::contain($associations, $override); + } + + /** + * @inheritDoc + */ + public function getContain(): array + { + $this->_deprecatedMethod('getContain()'); + + return parent::getContain(); + } + + /** + * @inheritDoc + */ + public function find(string $finder, array $options = []) + { + $this->_deprecatedMethod('find()'); + + return parent::find($finder, $options); + } + + /** + * @inheritDoc + */ + public function where($conditions = null, array $types = [], bool $overwrite = false) + { + $this->_deprecatedMethod('where()'); + + return parent::where($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function whereNotNull($fields) + { + $this->_deprecatedMethod('whereNotNull()'); + + return parent::whereNotNull($fields); + } + + /** + * @inheritDoc + */ + public function whereNull($fields) + { + $this->_deprecatedMethod('whereNull()'); + + return parent::whereNull($fields); + } + + /** + * @inheritDoc + */ + public function whereInList(string $field, array $values, array $options = []) + { + $this->_deprecatedMethod('whereInList()'); + + return parent::whereInList($field, $values, $options); + } + + /** + * @inheritDoc + */ + public function whereNotInList(string $field, array $values, array $options = []) + { + $this->_deprecatedMethod('whereNotInList()'); + + return parent::whereNotInList($field, $values, $options); + } + + /** + * @inheritDoc + */ + public function whereNotInListOrNull(string $field, array $values, array $options = []) + { + $this->_deprecatedMethod('whereNotInListOrNull()'); + + return parent::whereNotInListOrNull($field, $values, $options); + } + + /** + * @inheritDoc + */ + public function andWhere($conditions, array $types = []) + { + $this->_deprecatedMethod('andWhere()'); + + return parent::andWhere($conditions, $types); + } + + /** + * @inheritDoc + */ + public function order($fields, $overwrite = false) + { + $this->_deprecatedMethod('order()'); + + return parent::order($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function orderAsc($field, $overwrite = false) + { + $this->_deprecatedMethod('orderAsc()'); + + return parent::orderAsc($field, $overwrite); + } + + /** + * @inheritDoc + */ + public function orderDesc($field, $overwrite = false) + { + $this->_deprecatedMethod('orderDesc()'); + + return parent::orderDesc($field, $overwrite); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/SelectQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/SelectQuery.php new file mode 100644 index 000000000..368b6d7b7 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/SelectQuery.php @@ -0,0 +1,127 @@ +_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function insert(array $columns, array $types = []) + { + $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.'); + + return parent::insert($columns, $types); + } + + /** + * @inheritDoc + */ + public function into(string $table) + { + $this->_deprecatedMethod('into()', 'Use from() instead.'); + + return parent::into($table); + } + + /** + * @inheritDoc + */ + public function values($data) + { + $this->_deprecatedMethod('values()'); + + return parent::values($data); + } + + /** + * @inheritDoc + */ + public function update($table = null) + { + $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.'); + + return parent::update($table); + } + + /** + * @inheritDoc + */ + public function set($key, $value = null, $types = []) + { + $this->_deprecatedMethod('set()'); + + return parent::set($key, $value, $types); + } + + /** + * Sets the connection role. + * + * @param string $role Connection role ('read' or 'write') + * @return $this + */ + public function setConnectionRole(string $role) + { + assert($role === Connection::ROLE_READ || $role === Connection::ROLE_WRITE); + $this->connectionRole = $role; + + return $this; + } + + /** + * Sets the connection role to read. + * + * @return $this + */ + public function useReadRole() + { + return $this->setConnectionRole(Connection::ROLE_READ); + } + + /** + * Sets the connection role to write. + * + * @return $this + */ + public function useWriteRole() + { + return $this->setConnectionRole(Connection::ROLE_WRITE); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/UpdateQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/UpdateQuery.php new file mode 100644 index 000000000..ff25a89da --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/UpdateQuery.php @@ -0,0 +1,267 @@ +_type === 'update' && empty($this->_parts['update'])) { + $repository = $this->getRepository(); + $this->update($repository->getTable()); + } + + return parent::sql($binder); + } + + /** + * @inheritDoc + */ + public function delete(?string $table = null) + { + $this->_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function cache($key, $config = 'default') + { + $this->_deprecatedMethod('cache()', 'Use execute() instead.'); + + return parent::cache($key, $config); + } + + /** + * @inheritDoc + */ + public function all(): ResultSetInterface + { + $this->_deprecatedMethod('all()', 'Use execute() instead.'); + + return parent::all(); + } + + /** + * @inheritDoc + */ + public function select($fields = [], bool $overwrite = false) + { + $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.'); + + return parent::select($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function distinct($on = [], $overwrite = false) + { + $this->_deprecatedMethod('distinct()'); + + return parent::distinct($on, $overwrite); + } + + /** + * @inheritDoc + */ + public function modifier($modifiers, $overwrite = false) + { + $this->_deprecatedMethod('modifier()'); + + return parent::modifier($modifiers, $overwrite); + } + + /** + * @inheritDoc + */ + public function group($fields, $overwrite = false) + { + $this->_deprecatedMethod('group()'); + + return parent::group($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function having($conditions = null, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('having()'); + + return parent::having($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function andHaving($conditions, $types = []) + { + $this->_deprecatedMethod('andHaving()'); + + return parent::andHaving($conditions, $types); + } + + /** + * @inheritDoc + */ + public function page(int $num, ?int $limit = null) + { + $this->_deprecatedMethod('page()'); + + return parent::page($num, $limit); + } + + /** + * @inheritDoc + */ + public function offset($offset) + { + $this->_deprecatedMethod('offset()'); + + return parent::offset($offset); + } + + /** + * @inheritDoc + */ + public function union($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::union($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function unionAll($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::unionAll($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function insert(array $columns, array $types = []) + { + $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.'); + + return parent::insert($columns, $types); + } + + /** + * @inheritDoc + */ + public function into(string $table) + { + $this->_deprecatedMethod('into()', 'Use update() instead.'); + + return parent::into($table); + } + + /** + * @inheritDoc + */ + public function values($data) + { + $this->_deprecatedMethod('values()'); + + return parent::values($data); + } + + /** + * @inheritDoc + */ + public function from($tables = [], $overwrite = false) + { + $this->_deprecatedMethod('from()', 'Use update() instead.'); + + return parent::from($tables, $overwrite); + } + + /** + * @inheritDoc + */ + public function matching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('matching()'); + + return parent::matching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function notMatching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('notMatching()'); + + return parent::notMatching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function contain($associations, $override = false) + { + $this->_deprecatedMethod('contain()'); + + return parent::contain($associations, $override); + } + + /** + * @inheritDoc + */ + public function getContain(): array + { + $this->_deprecatedMethod('getContain()'); + + return parent::getContain(); + } + + /** + * @inheritDoc + */ + public function find(string $finder, array $options = []) + { + $this->_deprecatedMethod('find()'); + + return parent::find($finder, $options); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php b/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php index 1fe3cf69d..012c40025 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php +++ b/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php @@ -29,6 +29,9 @@ * This object is responsible for correctly nesting result keys reported from * the query, casting each field to the correct type and executing the extra * queries required for eager loading external associations. + * + * @template T of \Cake\Datasource\EntityInterface|array + * @implements \Cake\Datasource\ResultSetInterface */ class ResultSet implements ResultSetInterface { @@ -51,7 +54,8 @@ class ResultSet implements ResultSetInterface /** * Last record fetched from the statement * - * @var object|array + * @var \Cake\Datasource\EntityInterface|array + * @psalm-var T */ protected $_current; @@ -161,7 +165,7 @@ public function __construct(Query $query, StatementInterface $statement) { $repository = $query->getRepository(); $this->_statement = $statement; - $this->_driver = $query->getConnection()->getDriver(); + $this->_driver = $query->getConnection()->getDriver($query->getConnectionRole()); $this->_defaultTable = $repository; $this->_calculateAssociationMap($query); $this->_hydrate = $query->isHydrationEnabled(); @@ -182,7 +186,8 @@ public function __construct(Query $query, StatementInterface $statement) * * Part of Iterator interface. * - * @return object|array + * @return \Cake\Datasource\EntityInterface|array + * @psalm-return T */ #[\ReturnTypeWillChange] public function current() @@ -276,7 +281,8 @@ public function valid(): bool * * This method will also close the underlying statement cursor. * - * @return object|array|null + * @return \Cake\Datasource\EntityInterface|array|null + * @psalm-return T|null */ public function first() { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php b/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php index 37fbdf7d0..fe2b1cc76 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php @@ -19,6 +19,7 @@ use Cake\Datasource\EntityInterface; use Cake\ORM\Association; use Cake\ORM\Table; +use function Cake\Core\getTypeName; /** * Checks whether links to a given association exist / do not exist. diff --git a/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php b/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php index 8136b6d82..dd6a8ee4e 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php +++ b/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php @@ -23,6 +23,8 @@ use Cake\ORM\Rule\LinkConstraint; use Cake\ORM\Rule\ValidCount; use Cake\Utility\Inflector; +use function Cake\Core\getTypeName; +use function Cake\I18n\__d; /** * ORM flavoured rules checker. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Table.php b/app/vendor/cakephp/cakephp/src/ORM/Table.php index 1a37af224..b101dcddf 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Table.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Table.php @@ -40,13 +40,21 @@ use Cake\ORM\Exception\MissingEntityException; use Cake\ORM\Exception\PersistenceFailedException; use Cake\ORM\Exception\RolledbackTransactionException; +use Cake\ORM\Query\DeleteQuery; +use Cake\ORM\Query\InsertQuery; +use Cake\ORM\Query\SelectQuery; +use Cake\ORM\Query\UpdateQuery; use Cake\ORM\Rule\IsUnique; use Cake\Utility\Inflector; use Cake\Validation\ValidatorAwareInterface; use Cake\Validation\ValidatorAwareTrait; use Exception; use InvalidArgumentException; +use ReflectionMethod; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\Core\namespaceSplit; /** * Represents a single database table. @@ -515,11 +523,17 @@ public function getConnection(): Connection public function getSchema(): TableSchemaInterface { if ($this->_schema === null) { - $this->_schema = $this->_initializeSchema( - $this->getConnection() - ->getSchemaCollection() - ->describe($this->getTable()) - ); + $this->_schema = $this->getConnection() + ->getSchemaCollection() + ->describe($this->getTable()); + + $method = new ReflectionMethod($this, '_initializeSchema'); + if ($method->getDeclaringClass()->getName() != Table::class) { + deprecationWarning( + 'Table::_initializeSchema() is deprecated. Override `getSchema()` with a parent call instead.' + ); + $this->_schema = $this->_initializeSchema($this->_schema); + } if (Configure::read('debug')) { $this->checkAliasLengths(); } @@ -682,22 +696,34 @@ public function setDisplayField($field) /** * Returns the display field. * - * @return array|string|null + * @return array|string */ public function getDisplayField() { - if ($this->_displayField === null) { - $schema = $this->getSchema(); - $this->_displayField = $this->getPrimaryKey(); - foreach (['title', 'name', 'label'] as $field) { - if ($schema->hasColumn($field)) { - $this->_displayField = $field; - break; - } + if ($this->_displayField !== null) { + return $this->_displayField; + } + + $schema = $this->getSchema(); + foreach (['title', 'name', 'label'] as $field) { + if ($schema->hasColumn($field)) { + return $this->_displayField = $field; } } - return $this->_displayField; + foreach ($schema->columns() as $column) { + $columnSchema = $schema->getColumn($column); + if ( + $columnSchema && + $columnSchema['null'] !== true && + $columnSchema['type'] === 'string' && + !preg_match('/pass|token|secret/i', $column) + ) { + return $this->_displayField = $column; + } + } + + return $this->_displayField = $this->getPrimaryKey(); } /** @@ -1252,7 +1278,7 @@ public function belongsToMany(string $associated, array $options = []): BelongsT */ public function find(string $type = 'all', array $options = []): Query { - return $this->callFinder($type, $this->query()->select(), $options); + return $this->callFinder($type, $this->selectQuery()->select(), $options); } /** @@ -1697,9 +1723,56 @@ protected function _getFindOrCreateQuery($search): Query */ public function query(): Query { + deprecationWarning( + 'As of 4.5.0 using query() is deprecated. Instead use `insertQuery()`, ' . + '`deleteQuery()`, `selectQuery()` or `updateQuery()`. The query objects ' . + 'returned by these methods will emit deprecations that will become fatal errors in 5.0.' . + 'See https://book.cakephp.org/4/en/appendices/4-5-migration-guide.html for more information.' + ); + return new Query($this->getConnection(), $this); } + /** + * Creates a new DeleteQuery instance for a table. + * + * @return \Cake\ORM\Query\DeleteQuery + */ + public function deleteQuery(): DeleteQuery + { + return new DeleteQuery($this->getConnection(), $this); + } + + /** + * Creates a new InsertQuery instance for a table. + * + * @return \Cake\ORM\Query\InsertQuery + */ + public function insertQuery(): InsertQuery + { + return new InsertQuery($this->getConnection(), $this); + } + + /** + * Creates a new SelectQuery instance for a table. + * + * @return \Cake\ORM\Query\SelectQuery + */ + public function selectQuery(): SelectQuery + { + return new SelectQuery($this->getConnection(), $this); + } + + /** + * Creates a new UpdateQuery instance for a table. + * + * @return \Cake\ORM\Query\UpdateQuery + */ + public function updateQuery(): UpdateQuery + { + return new UpdateQuery($this->getConnection(), $this); + } + /** * Creates a new Query::subquery() instance for a table. * @@ -1716,8 +1789,7 @@ public function subquery(): Query */ public function updateAll($fields, $conditions): int { - $statement = $this->query() - ->update() + $statement = $this->updateQuery() ->set($fields) ->where($conditions) ->execute(); @@ -1731,8 +1803,7 @@ public function updateAll($fields, $conditions): int */ public function deleteAll($conditions): int { - $statement = $this->query() - ->delete() + $statement = $this->deleteQuery() ->where($conditions) ->execute(); $statement->closeCursor(); @@ -2072,7 +2143,8 @@ protected function _insert(EntityInterface $entity, array $data) return false; } - $statement = $this->query()->insert(array_keys($data)) + $statement = $this->insertQuery() + ->insert(array_keys($data)) ->values($data) ->execute(); @@ -2153,8 +2225,7 @@ protected function _update(EntityInterface $entity, array $data) throw new InvalidArgumentException($message); } - $statement = $this->query() - ->update() + $statement = $this->updateQuery() ->set($data) ->where($primaryKey) ->execute(); @@ -2494,8 +2565,7 @@ protected function _processDelete(EntityInterface $entity, ArrayObject $options) return $success; } - $statement = $this->query() - ->delete() + $statement = $this->deleteQuery() ->where($entity->extract($primaryKey)) ->execute(); diff --git a/app/vendor/cakephp/cakephp/src/Routing/Asset.php b/app/vendor/cakephp/cakephp/src/Routing/Asset.php index 88dee894c..ae8bd3bbe 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Asset.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Asset.php @@ -19,6 +19,7 @@ use Cake\Core\Configure; use Cake\Core\Plugin; use Cake\Utility\Inflector; +use function Cake\Core\pluginSplit; /** * Class for generating asset URLs. diff --git a/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php b/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php index 7ea24dde5..448490aaa 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php @@ -1,8 +1,10 @@ getMessage(), - $e->getCode() + $e->getCode(), + $e->getHeaders() ); } catch (DeprecatedRedirectException $e) { return new RedirectResponse( @@ -186,7 +189,10 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $handler->handle($request); } - $middleware = new MiddlewareQueue($matching); + $container = $this->app instanceof ContainerApplicationInterface + ? $this->app->getContainer() + : null; + $middleware = new MiddlewareQueue($matching, $container); $runner = new Runner(); return $runner->run($middleware, $request, $handler); diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php b/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php index 2444e4029..7122b8aea 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php @@ -31,9 +31,9 @@ class DashedRoute extends Route * Default values need to be inflected so that they match the inflections that * match() will create. * - * @var bool + * @var array|null */ - protected $_inflectedDefaults = false; + protected $_inflectedDefaults; /** * Camelizes the previously dashed plugin route taking into account plugin vendors @@ -97,12 +97,18 @@ public function parse(string $url, string $method = ''): ?array public function match(array $url, array $context = []): ?string { $url = $this->_dasherize($url); - if (!$this->_inflectedDefaults) { - $this->_inflectedDefaults = true; - $this->defaults = $this->_dasherize($this->defaults); + if ($this->_inflectedDefaults === null) { + $this->compile(); + $this->_inflectedDefaults = $this->_dasherize($this->defaults); } + $restore = $this->defaults; + try { + $this->defaults = $this->_inflectedDefaults; - return parent::match($url, $context); + return parent::match($url, $context); + } finally { + $this->defaults = $restore; + } } /** diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php b/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php index 6adaedc65..4a721724b 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php @@ -18,6 +18,7 @@ use ArrayAccess; use RuntimeException; +use function Cake\Core\getTypeName; /** * Matches entities to routes diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php b/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php index fdc552b60..2c819d078 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php @@ -30,9 +30,9 @@ class InflectedRoute extends Route * Default values need to be inflected so that they match the inflections that match() * will create. * - * @var bool + * @var array|null */ - protected $_inflectedDefaults = false; + protected $_inflectedDefaults; /** * Parses a string URL into an array. If it matches, it will convert the prefix, controller and @@ -76,12 +76,18 @@ public function parse(string $url, string $method = ''): ?array public function match(array $url, array $context = []): ?string { $url = $this->_underscore($url); - if (!$this->_inflectedDefaults) { - $this->_inflectedDefaults = true; - $this->defaults = $this->_underscore($this->defaults); + if ($this->_inflectedDefaults === null) { + $this->compile(); + $this->_inflectedDefaults = $this->_underscore($this->defaults); } + $restore = $this->defaults; + try { + $this->defaults = $this->_inflectedDefaults; - return parent::match($url, $context); + return parent::match($url, $context); + } finally { + $this->defaults = $restore; + } } /** diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php b/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php index 2315a07f2..15e6c07cb 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php @@ -19,6 +19,7 @@ use Cake\Http\Exception\BadRequestException; use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; +use function Cake\Core\deprecationWarning; /** * A single Route used by the Router to connect requests to diff --git a/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php b/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php index 25dcfd5eb..4f04e9773 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php +++ b/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php @@ -25,6 +25,7 @@ use Cake\Utility\Inflector; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\getTypeName; /** * Provides features for building routes inside scopes. diff --git a/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php b/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php index 8f96a5a99..c91e5ba9e 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php +++ b/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php @@ -21,6 +21,7 @@ use Cake\Routing\Route\Route; use Psr\Http\Message\ServerRequestInterface; use RuntimeException; +use function Cake\Core\deprecationWarning; /** * Contains a collection of routes. @@ -46,6 +47,13 @@ class RouteCollection */ protected $_named = []; + /** + * Routes indexed by static path. + * + * @var array> + */ + protected $staticPaths = []; + /** * Routes indexed by path prefix. * @@ -104,12 +112,17 @@ public function add(Route $route, array $options = []): void // Index path prefixes (for parsing) $path = $route->staticPath(); - $this->_paths[$path][] = $route; $extensions = $route->getExtensions(); if (count($extensions) > 0) { $this->setExtensions($extensions); } + + if ($path === $route->template) { + $this->staticPaths[$path][] = $route; + } + + $this->_paths[$path][] = $route; } /** @@ -119,17 +132,37 @@ public function add(Route $route, array $options = []): void * @param string $method The HTTP method to use. * @return array An array of request parameters parsed from the URL. * @throws \Cake\Routing\Exception\MissingRouteException When a URL has no matching route. + * @deprecated 4.5.0 Use parseRequest() instead. */ public function parse(string $url, string $method = ''): array { - $decoded = urldecode($url); - + deprecationWarning('4.5.0 - Use parseRequest() instead.'); $queryParameters = []; if (strpos($url, '?') !== false) { [$url, $qs] = explode('?', $url, 2); parse_str($qs, $queryParameters); } + $decoded = urldecode($url); + if ($decoded !== '/') { + $decoded = rtrim($decoded, '/'); + } + + if (isset($this->staticPaths[$decoded])) { + foreach ($this->staticPaths[$decoded] as $route) { + $r = $route->parse($url, $method); + if ($r === null) { + continue; + } + + if ($queryParameters) { + $r['?'] = $queryParameters; + } + + return $r; + } + } + // Sort path segments matching longest paths first. krsort($this->_paths); @@ -171,7 +204,33 @@ public function parse(string $url, string $method = ''): array public function parseRequest(ServerRequestInterface $request): array { $uri = $request->getUri(); - $urlPath = urldecode($uri->getPath()); + $urlPath = $uri->getPath(); + if (strpos($urlPath, '%') !== false) { + // decode urlencoded segments, but don't decode %2f aka / + $parts = explode('/', $urlPath); + $parts = array_map( + fn (string $part) => str_replace('/', '%2f', urldecode($part)), + $parts + ); + $urlPath = implode('/', $parts); + } + if ($urlPath !== '/') { + $urlPath = rtrim($urlPath, '/'); + } + if (isset($this->staticPaths[$urlPath])) { + foreach ($this->staticPaths[$urlPath] as $route) { + $r = $route->parseRequest($request); + if ($r === null) { + continue; + } + if ($uri->getQuery()) { + parse_str($uri->getQuery(), $queryParameters); + $r['?'] = array_merge($r['?'] ?? [], $queryParameters); + } + + return $r; + } + } // Sort path segments matching longest paths first. krsort($this->_paths); @@ -329,6 +388,8 @@ public function match(array $url, array $context): string /** * Get all the connected routes as a flat list. * + * Routes will not be returned in the order they were added. + * * @return array<\Cake\Routing\Route\Route> */ public function routes(): array diff --git a/app/vendor/cakephp/cakephp/src/Routing/Router.php b/app/vendor/cakephp/cakephp/src/Routing/Router.php index 9b4235cc3..d11b2788c 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Router.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Router.php @@ -25,6 +25,7 @@ use ReflectionMethod; use RuntimeException; use Throwable; +use function Cake\Core\deprecationWarning; /** * Parses the request URL into controller, action, and parameters. Uses the connected routes @@ -283,6 +284,7 @@ public static function reload(): void } } static::$_collection = new RouteCollection(); + static::$_routePaths = []; } /** @@ -401,7 +403,7 @@ protected static function _applyUrlFilters(array $url): array * - `_port` - Set the port if you need to create links on non-standard ports. * - `_full` - If true output of `Router::fullBaseUrl()` will be prepended to generated URLs. * - `#` - Allows you to set URL hash fragments. - * - `_ssl` - Set to true to convert the generated URL to https, or false to force http. + * - `_https` - Set to true to convert the generated URL to https, or false to force http. * - `_name` - Name of route. If you have setup named routes you can use this key * to specify it. * @@ -449,7 +451,13 @@ public static function url($url = null, bool $full = false): string } if (isset($url['_ssl'])) { - $url['_scheme'] = $url['_ssl'] === true ? 'https' : 'http'; + deprecationWarning('`_ssl` option is deprecated. Use `_https` instead.'); + $url['_https'] = $url['_ssl']; + unset($url['_ssl']); + } + + if (isset($url['_https'])) { + $url['_scheme'] = $url['_https'] === true ? 'https' : 'http'; } if (isset($url['_full']) && $url['_full'] === true) { @@ -458,7 +466,7 @@ public static function url($url = null, bool $full = false): string if (isset($url['#'])) { $frag = '#' . $url['#']; } - unset($url['_ssl'], $url['_full'], $url['#']); + unset($url['_https'], $url['_full'], $url['#']); $url = static::_applyUrlFilters($url); @@ -930,7 +938,9 @@ public static function plugin(string $name, $options = [], $callback = null): vo } /** - * Get the route scopes and their connected routes. + * Get the all of the routes currently connected. + * + * Routes will not always be returned in the order they were defined. * * @return array<\Cake\Routing\Route\Route> */ @@ -995,7 +1005,7 @@ protected static function unwrapShortString(array $url) * - Vendor/Cms.Management/Admin/Articles::view * * @param string $url Route path in [Plugin.][Prefix/]Controller::action format - * @return array + * @return array */ public static function parseRoutePath(string $url): array { @@ -1009,24 +1019,52 @@ public static function parseRoutePath(string $url): array (?[a-z0-9]+) :: (?[a-z0-9_]+) + (?(?:/(?:[a-z][a-z0-9-_]*=)? + (?:([a-z0-9-_=]+)|(["\'][^\'"]+[\'"])) + )+/?)? $#ix'; if (!preg_match($regex, $url, $matches)) { throw new InvalidArgumentException("Could not parse a string route path `{$url}`."); } - $defaults = []; - + $defaults = [ + 'controller' => $matches['controller'], + 'action' => $matches['action'], + ]; if ($matches['plugin'] !== '') { $defaults['plugin'] = $matches['plugin']; } if ($matches['prefix'] !== '') { $defaults['prefix'] = $matches['prefix']; } - $defaults['controller'] = $matches['controller']; - $defaults['action'] = $matches['action']; - static::$_routePaths[$url] = $defaults; + if (isset($matches['params']) && $matches['params'] !== '') { + $paramsArray = explode('/', trim($matches['params'], '/')); + foreach ($paramsArray as $param) { + if (strpos($param, '=') !== false) { + if (!preg_match('/(?.+?)=(?.*)/', $param, $paramMatches)) { + throw new InvalidArgumentException( + "Could not parse a key=value from `{$param}` in route path `{$url}`." + ); + } + $paramKey = $paramMatches['key']; + if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $paramKey)) { + throw new InvalidArgumentException( + "Param key `{$paramKey}` is not valid in route path `{$url}`." + ); + } + $defaults[$paramKey] = trim($paramMatches['value'], '\'"'); + } else { + $defaults[] = $param; + } + } + } + // Only cache 200 routes per request. Beyond that we could + // be soaking up too much memory. + if (count(static::$_routePaths) < 200) { + static::$_routePaths[$url] = $defaults; + } return $defaults; } diff --git a/app/vendor/cakephp/cakephp/src/Routing/functions.php b/app/vendor/cakephp/cakephp/src/Routing/functions.php index d43f6b788..310ce6990 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/functions.php +++ b/app/vendor/cakephp/cakephp/src/Routing/functions.php @@ -11,30 +11,54 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @link https://cakephp.org CakePHP(tm) Project - * @since 4.1.0 + * @since 4.5.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ +// phpcs:disable PSR1.Files.SideEffects +namespace Cake\Routing; -use Cake\Routing\Router; +/** + * Convenience wrapper for Router::url(). + * + * @param \Psr\Http\Message\UriInterface|array|string|null $url An array specifying any of the following: + * 'controller', 'action', 'plugin' additionally, you can provide routed + * elements or query string parameters. If string it can be name any valid url + * string or it can be an UriInterface instance. + * @param bool $full If true, the full base URL will be prepended to the result. + * Default is false. + * @return string Full translated URL with base path. + * @throws \Cake\Core\Exception\CakeException When the route name is not found + * @see \Cake\Routing\Router::url() + * @since 4.5.0 + */ +function url($url = null, bool $full = false): string +{ + return Router::url($url, $full); +} -if (!function_exists('urlArray')) { - /** - * Returns an array URL from a route path string. - * - * @param string $path Route path. - * @param array $params An array specifying any additional parameters. - * Can be also any special parameters supported by `Router::url()`. - * @return array URL - * @see \Cake\Routing\Router::pathUrl() - */ - function urlArray(string $path, array $params = []): array - { - $url = Router::parseRoutePath($path); - $url += [ - 'plugin' => false, - 'prefix' => false, - ]; +/** + * Returns an array URL from a route path string. + * + * @param string $path Route path. + * @param array $params An array specifying any additional parameters. + * Can be also any special parameters supported by `Router::url()`. + * @return array URL + * @see \Cake\Routing\Router::pathUrl() + */ +function urlArray(string $path, array $params = []): array +{ + $url = Router::parseRoutePath($path); + $url += [ + 'plugin' => false, + 'prefix' => false, + ]; + + return $url + $params; +} - return $url + $params; - } +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; } diff --git a/app/vendor/cakephp/cakephp/src/Routing/functions_global.php b/app/vendor/cakephp/cakephp/src/Routing/functions_global.php new file mode 100644 index 000000000..e13958b0c --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Routing/functions_global.php @@ -0,0 +1,56 @@ +groupBy(function (EventInterface $event): string { return $event->getName(); }) @@ -111,6 +112,6 @@ public function matches($other): bool */ public function toString(): string { - return 'was fired with ' . $this->_dataKey . ' matching ' . (string)$this->_dataValue; + return "was fired with `{$this->_dataKey}` matching `" . json_encode($this->_dataValue) . '`'; } } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php index 0522f86cd..2edbec970 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php @@ -55,7 +55,7 @@ public function __construct(?Response $response, string $cookieName) */ public function matches($other): bool { - $cookie = $this->response->getCookie($this->cookieName); + $cookie = $this->readCookie($this->cookieName); return $cookie !== null && $cookie['value'] === $other; } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php index 370c40c6d..bd31234f4 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php @@ -35,7 +35,7 @@ class CookieSet extends ResponseBase */ public function matches($other): bool { - $cookie = $this->response->getCookie($other); + $cookie = $this->readCookie($other); return $cookie !== null && $cookie['value'] !== ''; } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php index c17f9956d..5b43b0124 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php @@ -15,6 +15,7 @@ */ namespace Cake\TestSuite\Constraint\Response; +use Cake\Http\Cookie\CookieCollection; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Constraint\Constraint; use Psr\Http\Message\ResponseInterface; @@ -54,4 +55,24 @@ protected function _getBodyAsString(): string { return (string)$this->response->getBody(); } + + /** + * Read a cookie from either the response cookie collection, + * or headers + * + * @param string $name The name of the cookie you want to read. + * @return array|null Null if the cookie does not exist, array with `value` as the only key. + */ + protected function readCookie(string $name): ?array + { + if (method_exists($this->response, 'getCookie')) { + return $this->response->getCookie($name); + } + $cookies = CookieCollection::createFromHeader($this->response->getHeader('Set-Cookie')); + if (!$cookies->has($name)) { + return null; + } + + return $cookies->get($name)->toArray(); + } } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php index 7e564fc3d..8cd3f99bf 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php @@ -1,6 +1,10 @@ */ $className = $fixture; - /** @psalm-suppress PossiblyFalseArgument */ $name = preg_replace('/Fixture\z/', '', substr(strrchr($fixture, '\\'), 1)); } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php index 3a97b1bd6..5e200f207 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php @@ -92,12 +92,58 @@ public function loadSqlFiles( } /** - * Load and apply CakePHP-specific schema file. + * Load and apply CakePHP schema file. + * + * This method will process the array returned by `$file` and treat + * the contents as a list of table schema. + * + * An example table is: + * + * ``` + * return [ + * 'articles' => [ + * 'columns' => [ + * 'id' => [ + * 'type' => 'integer', + * ], + * 'author_id' => [ + * 'type' => 'integer', + * 'null' => true, + * ], + * 'title' => [ + * 'type' => 'string', + * 'null' => true, + * ], + * 'body' => 'text', + * 'published' => [ + * 'type' => 'string', + * 'length' => 1, + * 'default' => 'N', + * ], + * ], + * 'constraints' => [ + * 'primary' => [ + * 'type' => 'primary', + * 'columns' => [ + * 'id', + * ], + * ], + * ], + * ], + * ]; + * ``` + * + * This schema format can be useful for plugins that want to include + * tables to test against but don't need to include production + * ready schema via migrations. Applications should favour using migrations + * or SQL dump files over this format for ease of maintenance. + * + * A more complete example can be found in `tests/schema.php`. * * @param string $file Schema file * @param string $connectionName Connection name + * @throws \InvalidArgumentException For missing table name(s). * @return void - * @internal */ public function loadInternalFile(string $file, string $connectionName = 'test'): void { @@ -112,8 +158,15 @@ public function loadInternalFile(string $file, string $connectionName = 'test'): $connection = ConnectionManager::get($connectionName); $connection->disableConstraints(function ($connection) use ($tables) { - foreach ($tables as $table) { - $schema = new TableSchema($table['table'], $table['columns']); + foreach ($tables as $tableName => $table) { + $name = $table['table'] ?? $tableName; + if (!is_string($name)) { + throw new InvalidArgumentException( + sprintf('`%s` is not a valid table name. Either use a string key for the table definition' + . '(`\'articles\' => [...]`) or define the `table` key in the table definition.', $name) + ); + } + $schema = new TableSchema($name, $table['columns']); if (isset($table['indexes'])) { foreach ($table['indexes'] as $key => $index) { $schema->addIndex($key, $index); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php index a4f0fde86..7eefb8ac4 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php @@ -26,6 +26,7 @@ use Cake\ORM\Locator\LocatorAwareTrait; use Cake\Utility\Inflector; use Exception; +use function Cake\Core\namespaceSplit; /** * Cake TestFixture is responsible for building and destroying tables to be used @@ -335,7 +336,8 @@ public function insert(ConnectionInterface $connection) { if (!empty($this->records)) { [$fields, $values, $types] = $this->_getRecords(); - $query = $connection->newQuery() + /** @var \Cake\Database\Connection $connection */ + $query = $connection->insertQuery() ->insert($fields, $types) ->into($this->sourceName()); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php index c20b154db..0bafe7e65 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php @@ -1,6 +1,10 @@ $query, 'REQUEST_URI' => $url, ]; - if (!empty($hostInfo['ssl'])) { + if (!empty($hostInfo['https'])) { $env['HTTPS'] = 'on'; } if (isset($hostInfo['host'])) { @@ -728,7 +728,7 @@ protected function _url(string $url): array $hostData['host'] = $uri->getHost(); } if ($uri->getScheme()) { - $hostData['ssl'] = $uri->getScheme() === 'https'; + $hostData['https'] = $uri->getScheme() === 'https'; } return [$path, $query, $hostData]; @@ -1248,6 +1248,22 @@ public function assertCookie($expected, string $name, string $message = ''): voi $this->assertThat($expected, new CookieEquals($this->_response, $name), $verboseMessage); } + /** + * Asserts that a cookie is set. + * + * Useful when you're working with cookies that have obfuscated values + * but the cookie being set is important. + * + * @param string $name The cookie name. + * @param string $message The failure message that will be appended to the generated message. + * @return void + */ + public function assertCookieIsSet(string $name, string $message = ''): void + { + $verboseMessage = $this->extractVerboseMessage($message); + $this->assertThat($name, new CookieSet($this->_response), $verboseMessage); + } + /** * Asserts a cookie has not been set in the response * diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php index e598b17f4..d386817d2 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php @@ -1,6 +1,10 @@ _capturedError = null; + set_error_handler( + function (int $code, string $description, string $file, int $line) { + $trace = Debugger::trace(['start' => 1, 'format' => 'points']); + $this->_capturedError = new PhpError($code, $description, $file, $line, $trace); + + return true; + }, + $errorLevel + ); + + try { + $callable(); + } finally { + restore_error_handler(); + error_reporting($default); + } + if ($this->_capturedError === null) { + $this->fail('No error was captured'); + } + /** @var \Cake\Error\PhpError $this->_capturedError */ + return $this->_capturedError; + } + /** * Helper method for check deprecation methods * @@ -208,9 +256,6 @@ public function deprecated(callable $callable): void /** @var bool $deprecation */ $deprecation = false; - /** - * @psalm-suppress InvalidArgument - */ $previousHandler = set_error_handler( function ($code, $message, $file, $line, $context = null) use (&$previousHandler, &$deprecation): bool { if ($code == E_USER_DEPRECATED) { @@ -763,7 +808,6 @@ public function assertHtml(array $expected, string $string, bool $fullDebug = fa continue; } foreach ($tags as $tag => $attributes) { - /** @psalm-suppress PossiblyFalseArgument */ $regex[] = [ sprintf('Open %s tag', $tag), sprintf('[\s]*<%s', preg_quote($tag, '/')), @@ -810,7 +854,6 @@ public function assertHtml(array $expected, string $string, bool $fullDebug = fa 'attrs' => $attrs, ]; } - /** @psalm-suppress PossiblyFalseArgument */ $regex[] = [ sprintf('End %s tag', $tag), '[\s]*\/?[\s]*>[\n\r]*', @@ -833,7 +876,6 @@ public function assertHtml(array $expected, string $string, bool $fullDebug = fa } // If 'attrs' is not present then the array is just a regular int-offset one - /** @psalm-suppress PossiblyUndefinedArrayOffset */ [$description, $expressions, $itemNum] = $assertion; $expression = ''; foreach ((array)$expressions as $expression) { diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php index 440530d7d..f51e74590 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php @@ -22,6 +22,9 @@ use PHPUnit\Framework\Warning; use Throwable; +// phpcs:disable +deprecationWarning('4.5.0 - TestListenerTrait is deprecated, as PHPUnit is removing support for listeners.'); + /** * Implements empty default methods for PHPUnit\Framework\TestListener. */ diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php b/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php index e5a18c215..eb96dffe9 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php @@ -21,6 +21,7 @@ use Cake\Filesystem\Filesystem; use PHPUnit\Framework\TestSuite as BaseTestSuite; use SplFileInfo; +use function Cake\Core\deprecationWarning; /** * A class to contain test cases and run them with shared fixtures @@ -35,6 +36,7 @@ class TestSuite extends BaseTestSuite */ public function addTestDirectory(string $directory = '.'): void { + deprecationWarning('4.5.0 - TestSuite is deprecated as PHPunit is removing support for testsuites.'); $fs = new Filesystem(); $files = $fs->find($directory, '/\.php$/'); foreach ($files as $file => $fileInfo) { @@ -50,6 +52,7 @@ public function addTestDirectory(string $directory = '.'): void */ public function addTestDirectoryRecursive(string $directory = '.'): void { + deprecationWarning('4.5.0 - TestSuite is deprecated as PHPunit is removing support for testsuites.'); $fs = new Filesystem(); $files = $fs->findRecursive($directory, function (SplFileInfo $current) { $file = $current->getFilename(); diff --git a/app/vendor/cakephp/cakephp/src/Utility/Hash.php b/app/vendor/cakephp/cakephp/src/Utility/Hash.php index 782f2c5ca..32781929f 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Hash.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Hash.php @@ -336,7 +336,10 @@ public static function insert(array $data, string $path, $values = null): array foreach ($data as $k => $v) { if (static::_matchToken($k, $token)) { - if (!$conditions || static::_matches($v, $conditions)) { + if ( + !$conditions || + ((is_array($v) || $v instanceof ArrayAccess) && static::_matches($v, $conditions)) + ) { $data[$k] = $nextPath ? static::insert($v, $nextPath, $values) : array_merge($v, (array)$values); @@ -1154,10 +1157,11 @@ public static function mergeDiff(array $data, array $compare): array * * @param array $data List to normalize * @param bool $assoc If true, $data will be converted to an associative array. + * @param mixed $default The default value to use when a top level numeric key is converted to associative form. * @return array * @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::normalize */ - public static function normalize(array $data, bool $assoc = true): array + public static function normalize(array $data, bool $assoc = true, $default = null): array { $keys = array_keys($data); $count = count($keys); @@ -1175,7 +1179,7 @@ public static function normalize(array $data, bool $assoc = true): array $newList = []; for ($i = 0; $i < $count; $i++) { if (is_int($keys[$i])) { - $newList[$data[$keys[$i]]] = null; + $newList[$data[$keys[$i]]] = $default; } else { $newList[$keys[$i]] = $data[$keys[$i]]; } diff --git a/app/vendor/cakephp/cakephp/src/Utility/Inflector.php b/app/vendor/cakephp/cakephp/src/Utility/Inflector.php index 9cb8c1f44..8abcd079d 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Inflector.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Inflector.php @@ -464,7 +464,7 @@ public static function delimit(string $string, string $delimiter = '_'): string } /** - * Returns corresponding table name for given model $className. ("people" for the model class "Person"). + * Returns corresponding table name for given model $className. ("people" for the class name "Person"). * * @param string $className Name of class to get database table name for * @return string Name of the database table for given class @@ -483,7 +483,7 @@ public static function tableize(string $className): string } /** - * Returns Cake model class name ("Person" for the database table "people".) for given database table. + * Returns a singular, CamelCase inflection for given database table. ("Person" for the table name "people") * * @param string $tableName Name of database table to get class name for * @return string Class name diff --git a/app/vendor/cakephp/cakephp/src/Utility/Text.php b/app/vendor/cakephp/cakephp/src/Utility/Text.php index 95cf22c9e..7116b0dec 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Text.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Text.php @@ -19,6 +19,8 @@ use Cake\Core\Exception\CakeException; use InvalidArgumentException; use Transliterator; +use function Cake\Core\deprecationWarning; +use function Cake\I18n\__d; /** * Text handling methods. diff --git a/app/vendor/cakephp/cakephp/src/Utility/Xml.php b/app/vendor/cakephp/cakephp/src/Utility/Xml.php index 069177af4..53ddfbda7 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Xml.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Xml.php @@ -475,7 +475,6 @@ protected static function _toArray(SimpleXMLElement $xml, array &$parentData, st } foreach ($xml->children($namespace, true) as $child) { - /** @psalm-suppress PossiblyNullArgument */ static::_toArray($child, $data, $namespace, $namespaces); } } diff --git a/app/vendor/cakephp/cakephp/src/Validation/Validation.php b/app/vendor/cakephp/cakephp/src/Validation/Validation.php index 6ca684f3a..043347bfa 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/Validation.php +++ b/app/vendor/cakephp/cakephp/src/Validation/Validation.php @@ -25,6 +25,7 @@ use NumberFormatter; use Psr\Http\Message\UploadedFileInterface; use RuntimeException; +use function Cake\Core\deprecationWarning; /** * Validation Class. Used for validation of model data diff --git a/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php b/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php index a16ab6b6a..69808d138 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php +++ b/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php @@ -25,6 +25,9 @@ /** * ValidationSet object. Holds all validation rules for a field and exposes * methods to dynamically add or remove validation rules + * + * @template-implements \ArrayAccess + * @template-implements \IteratorAggregate */ class ValidationSet implements ArrayAccess, IteratorAggregate, Countable { diff --git a/app/vendor/cakephp/cakephp/src/Validation/Validator.php b/app/vendor/cakephp/cakephp/src/Validation/Validator.php index e968a4c96..51764b486 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/Validator.php +++ b/app/vendor/cakephp/cakephp/src/Validation/Validator.php @@ -23,6 +23,9 @@ use IteratorAggregate; use Psr\Http\Message\UploadedFileInterface; use Traversable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\I18n\__d; /** * Validator object encapsulates all methods related to data validations for a model @@ -31,6 +34,8 @@ * Implements ArrayAccess to easily modify rules in the set * * @link https://book.cakephp.org/4/en/core-libraries/validation.html + * @template-implements \ArrayAccess + * @template-implements \IteratorAggregate */ class Validator implements ArrayAccess, IteratorAggregate, Countable { @@ -193,7 +198,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable */ public function __construct() { - $this->_useI18n = function_exists('__d'); + $this->_useI18n = function_exists('\Cake\I18n\__d'); $this->_providers = self::$_defaultProviders; } @@ -2349,8 +2354,30 @@ public function integer(string $field, ?string $message = null, $when = null) * @see \Cake\Validation\Validation::isArray() * @return $this */ + public function array(string $field, ?string $message = null, $when = null) + { + $extra = array_filter(['on' => $when, 'message' => $message]); + + return $this->add($field, 'array', $extra + [ + 'rule' => 'isArray', + ]); + } + + /** + * Add a validation rule to ensure that a field contains an array. + * + * @param string $field The field you want to apply the rule to. + * @param string|null $message The error message when the rule fails. + * @param callable|string|null $when Either 'create' or 'update' or a callable that returns + * true when the validation rule should be applied. + * @see \Cake\Validation\Validation::isArray() + * @return $this + * @deprecated 4.5.0 Use Validator::array() instead. + */ public function isArray(string $field, ?string $message = null, $when = null) { + deprecationWarning('`Validator::isArray()` is deprecated, use `Validator::array()` instead'); + $extra = array_filter(['on' => $when, 'message' => $message]); return $this->add($field, 'isArray', $extra + [ diff --git a/app/vendor/cakephp/cakephp/src/View/Cell.php b/app/vendor/cakephp/cakephp/src/View/Cell.php index 49cf528b5..9908a74f2 100644 --- a/app/vendor/cakephp/cakephp/src/View/Cell.php +++ b/app/vendor/cakephp/cakephp/src/View/Cell.php @@ -245,7 +245,6 @@ protected function _cacheConfig(string $action, ?string $template = null): array return $default; } - /** @psalm-suppress PossiblyFalseOperand */ return $this->_cache + $default; } diff --git a/app/vendor/cakephp/cakephp/src/View/CellTrait.php b/app/vendor/cakephp/cakephp/src/View/CellTrait.php index 5252c98c9..78d75aacc 100644 --- a/app/vendor/cakephp/cakephp/src/View/CellTrait.php +++ b/app/vendor/cakephp/cakephp/src/View/CellTrait.php @@ -19,6 +19,7 @@ use Cake\Core\App; use Cake\Utility\Inflector; use Cake\View\Exception\MissingCellException; +use function Cake\Core\pluginSplit; /** * Provides cell() method for usage in Controller and View classes. diff --git a/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php b/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php index 9a9a54373..b276c0f80 100644 --- a/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php +++ b/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php @@ -56,7 +56,7 @@ public function __construct( * Get the passed in attributes * * @return array - * @psalm-return array{name: string, file: string, paths: array} + * @psalm-return array{name: string, file: string, paths: array} */ public function getAttributes(): array { diff --git a/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php b/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php index 2cd422e04..cf50c7a22 100644 --- a/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php +++ b/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php @@ -87,7 +87,7 @@ public function formatMessage(): string * Get the passed in attributes * * @return array - * @psalm-return array{file: string, paths: array} + * @psalm-return array{file: string, paths: array} */ public function getAttributes(): array { diff --git a/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php b/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php index 8271c92b9..1e197569e 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php @@ -17,6 +17,8 @@ namespace Cake\View\Form; use Cake\Utility\Hash; +use function Cake\Core\deprecationWarning; +use function Cake\I18n\__d; /** * Provides a basic array based context provider for FormHelper. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php b/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php index d24fa3de9..482fa85d2 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php @@ -21,6 +21,7 @@ use Cake\Form\Form; use Cake\Http\ServerRequest; use RuntimeException; +use function Cake\Core\getTypeName; /** * Factory for getting form context instance based on provided data. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php b/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php index 87e2ce4e1..728ade06e 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php @@ -27,6 +27,8 @@ use Cake\Validation\Validator; use RuntimeException; use Traversable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\namespaceSplit; /** * Provides a form context around a single entity and its relations. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php b/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php index 007e2dcb1..731cc045e 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php @@ -19,6 +19,7 @@ use Cake\Core\Exception\CakeException; use Cake\Form\Form; use Cake\Utility\Hash; +use function Cake\Core\deprecationWarning; /** * Provides a context provider for {@link \Cake\Form\Form} instances. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php b/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php index 5adf5639e..8defaa128 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php @@ -16,6 +16,8 @@ */ namespace Cake\View\Form; +use function Cake\Core\deprecationWarning; + /** * Provides a context provider that does nothing. * diff --git a/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php b/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php index 2b298118d..77bc7451c 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php @@ -30,6 +30,10 @@ use Cake\View\Widget\WidgetLocator; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\h; +use function Cake\I18n\__; +use function Cake\I18n\__d; /** * Form helper library. @@ -113,9 +117,9 @@ class FormHelper extends Helper // Wrapper content used to hide other content. 'hiddenBlock' => '
{{content}}
', // Generic input element. - 'input' => '', + 'input' => '', // Submit input element. - 'inputSubmit' => '', + 'inputSubmit' => '', // Container element used by control(). 'inputContainer' => '
{{content}}
', // Container element used by control() when a field has an error. @@ -150,6 +154,8 @@ class FormHelper extends Helper 'confirmJs' => '{{confirm}}', // selected class 'selectedClass' => 'selected', + // required class + 'requiredClass' => 'required', ], // set HTML5 validation message to custom required/empty messages 'autoSetCustomValidity' => true, @@ -616,7 +622,7 @@ public function secure(array $fields = [], array $secureAttributes = []): string $tokenData = $this->formProtector->buildTokenData( $this->_lastAction, - $this->_View->getRequest()->getSession()->id() + $this->_getFormProtectorSessionId() ); $tokenFields = array_merge($secureAttributes, [ 'value' => $tokenData['fields'], @@ -636,6 +642,17 @@ public function secure(array $fields = [], array $secureAttributes = []): string return $this->formatTemplate('hiddenBlock', ['content' => $out]); } + /** + * Get Session id for FormProtector + * Must be the same as in FormProtectionComponent + * + * @return string + */ + protected function _getFormProtectorSessionId(): string + { + return $this->_View->getRequest()->getSession()->id(); + } + /** * Add to the list of fields that are currently unlocked. * @@ -1133,6 +1150,7 @@ public function control(string $fieldName, array $options = []): string 'content' => $result, 'error' => $error, 'errorSuffix' => $errorSuffix, + 'label' => $label, 'options' => $options, ]); @@ -1180,7 +1198,8 @@ protected function _inputContainerTemplate(array $options): string return $this->formatTemplate($inputContainerTemplate, [ 'content' => $options['content'], 'error' => $options['error'], - 'required' => $options['options']['required'] ? ' required' : '', + 'label' => $options['label'] ?? '', + 'required' => $options['options']['required'] ? ' ' . $this->templater()->get('requiredClass') : '', 'type' => $options['options']['type'], 'templateVars' => $options['options']['templateVars'] ?? [], ]); @@ -1377,9 +1396,13 @@ protected function setRequiredAndCustomValidity(string $fieldName, array $option $options['templateVars']['customValidityMessage'] = $message; if ($this->getConfig('autoSetCustomValidity')) { + $condition = 'this.value'; + if ($options['type'] === 'checkbox') { + $condition = 'this.checked'; + } $options['data-validity-message'] = $message; $options['oninvalid'] = "this.setCustomValidity(''); " - . 'if (!this.value) this.setCustomValidity(this.dataset.validityMessage)'; + . "if (!{$condition}) this.setCustomValidity(this.dataset.validityMessage)"; $options['oninput'] = "this.setCustomValidity('')"; } } @@ -1581,8 +1604,8 @@ public function radio(string $fieldName, iterable $options = [], array $attribut /** * Missing method handler - implements various simple input types. Is used to create inputs - * of various types. e.g. `$this->Form->text();` will create `` while - * `$this->Form->range();` will create `` + * of various types. e.g. `$this->Form->text();` will create `` while + * `$this->Form->range();` will create `` * * ### Usage * @@ -1592,7 +1615,7 @@ public function radio(string $fieldName, iterable $options = [], array $attribut * * Will make an input like: * - * `` + * `` * * The first argument to an input type should always be the fieldname, in `Model.field` format. * The second argument should always be an array of attributes for the input. @@ -1796,7 +1819,7 @@ public function postButton(string $title, $url, array $options = []): string * @param array|string|null $url Cake-relative URL or array of URL parameters, or * external URL (starts with http://) * @param array $options Array of HTML attributes. - * @return string An `` element. + * @return string An `` element. * @link https://book.cakephp.org/4/en/views/helpers/form.html#creating-standalone-buttons-and-post-links */ public function postLink(string $title, $url = null, array $options = []): string @@ -1892,7 +1915,7 @@ public function postLink(string $title, $url = null, array $options = []): strin } /** - * Creates a submit button element. This method will generate `` elements that + * Creates a submit button element. This method will generate `` elements that * can be used to submit, and reset forms by using $options. image submits can be created by supplying an * image path for $caption. * diff --git a/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php b/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php index aa2d5ed02..7b62136b4 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php @@ -19,6 +19,7 @@ use Cake\Core\Configure; use Cake\View\Helper; use Cake\View\StringTemplateTrait; +use function Cake\Core\h; /** * Html Helper class for easy use of HTML widgets. @@ -46,11 +47,11 @@ class HtmlHelper extends Helper */ protected $_defaultConfig = [ 'templates' => [ - 'meta' => '', - 'metalink' => '', + 'meta' => '', + 'metalink' => '', 'link' => '{{content}}', 'mailto' => '{{content}}', - 'image' => '', + 'image' => '', 'tableheader' => '{{content}}', 'tableheaderrow' => '{{content}}', 'tablecell' => '{{content}}', @@ -64,9 +65,9 @@ class HtmlHelper extends Helper 'tagselfclosing' => '<{{tag}}{{attrs}}/>', 'para' => '{{content}}

', 'parastart' => '', - 'css' => '', + 'css' => '', 'style' => '{{content}}', - 'charset' => '', + 'charset' => '', 'ul' => '{{content}}', 'ol' => '{{content}}', 'li' => '{{content}}', @@ -129,7 +130,7 @@ class HtmlHelper extends Helper * @param array|string|null $content The address of the external resource or string for content attribute * @param array $options Other attributes for the generated tag. If the type attribute is html, * rss, atom, or icon, the mime-type is returned. - * @return string|null A completed `` element, or null if the element was sent to a block. + * @return string|null A completed `` element, or null if the element was sent to a block. * @link https://book.cakephp.org/4/en/views/helpers/html.html#creating-meta-tags */ public function meta($type, $content = null, array $options = []): ?string @@ -247,7 +248,7 @@ public function charset(?string $charset = null): string * @param array|string|null $url Cake-relative URL or array of URL parameters, or * external URL (starts with http://) * @param array $options Array of options and HTML attributes. - * @return string An `` element. + * @return string An `` element. * @link https://book.cakephp.org/4/en/views/helpers/html.html#creating-links */ public function link($title, $url = null, array $options = []): string @@ -314,7 +315,7 @@ public function link($title, $url = null, array $options = []): string * @param array $params An array specifying any additional parameters. * Can be also any special parameters supported by `Router::url()`. * @param array $options Array of options and HTML attributes. - * @return string An `` element. + * @return string An `` element. * @see \Cake\Routing\Router::pathUrl() * @link https://book.cakephp.org/4/en/views/helpers/html.html#creating-links */ @@ -371,7 +372,7 @@ public function linkFromPath(string $title, string $path, array $params = [], ar * CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot * of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css. * @param array $options Array of options and HTML arguments. - * @return string|null CSS `` or ` @@ -282,29 +345,26 @@
-
- element('exception_stack_trace_nav') ?> -
-
- fetch('subheading')): ?> -

- fetch('subheading') ?> -

- + fetch('subheading')): ?> +

+ fetch('subheading') ?> +

+ - element('exception_stack_trace'); ?> + fetch('file')): ?> +
+ fetch('file') ?> +
+ -
- fetch('file') ?> -
+ element('dev_error_stacktrace'); ?> - fetch('templateName')): ?> -

- If you want to customize this error message, create - fetch('templateName') ?> -

- -
+ fetch('templateName')): ?> +

+ If you want to customize this error message, create + fetch('templateName') ?> +

+
+ + + + hello + + + + + + + + + + + + + + + + + + + + + +section as $section) { + ?> + + + + + + section as $section) { + ?> +
+ + + + + + + + +?> + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +<?php echo $title; ?> + + + + + hello + + + + + + + + + + + + + + + + + + + +section as $section) { + ?> +
+ + + + + section as $section) { + ?> +
+ + + + + + + + + + + + +?> + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.15.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.15.inc new file mode 100644 index 000000000..d8f051277 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.15.inc @@ -0,0 +1,9 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.16.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.16.inc new file mode 100644 index 000000000..754c241b8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.16.inc @@ -0,0 +1,8 @@ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.17.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.17.inc new file mode 100644 index 000000000..71de17bfb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.17.inc @@ -0,0 +1,8 @@ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc new file mode 100644 index 000000000..3d61d4859 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc @@ -0,0 +1,15 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc.fixed new file mode 100644 index 000000000..8c906d40c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc.fixed @@ -0,0 +1,13 @@ + + +
+ +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc new file mode 100644 index 000000000..34db64d60 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc @@ -0,0 +1,17 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc.fixed new file mode 100644 index 000000000..b1738db57 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc.fixed @@ -0,0 +1,15 @@ + + +
+ +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc new file mode 100644 index 000000000..755fd355b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc @@ -0,0 +1,7 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc.fixed new file mode 100644 index 000000000..e9073da91 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc.fixed @@ -0,0 +1,7 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc new file mode 100644 index 000000000..28cdbdaf7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc @@ -0,0 +1,15 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc.fixed new file mode 100644 index 000000000..fcc24a278 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc.fixed @@ -0,0 +1,16 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc new file mode 100644 index 000000000..1da67a2ea --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc @@ -0,0 +1,15 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc.fixed new file mode 100644 index 000000000..d7487b507 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc.fixed @@ -0,0 +1,16 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.22.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.22.inc new file mode 100644 index 000000000..5196a3b45 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.22.inc @@ -0,0 +1,30 @@ +
Inline HTML with indent to demonstrate the bug in the indent calculation.
+ + + + + + + + +Inline HTML with indent to demonstrate the bug in the indent calculation.
+ + + + + + + + + + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.24.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.24.inc new file mode 100644 index 000000000..dc1749c33 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.24.inc @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<?= $title ?> + + + + + hello + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +// Safeguard fixing when there is no whitespace between the close tag and the contents. + + + + + + + + + +<?= $title; ?> + + + + + hello + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Safeguard fixing when there is no whitespace between the close tag and the contents. + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.4.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.4.inc.fixed new file mode 100644 index 000000000..b7985cc50 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.4.inc.fixed @@ -0,0 +1,7 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.5.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.5.inc new file mode 100644 index 000000000..f4d8d8a0c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.5.inc @@ -0,0 +1,48 @@ + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + - - -<?php echo $title ?> - - - - - hello - - - - - - - - - - - - - - - - - - - - - -section as $section) { - ?> -
- - - - - section as $section) { - ?> -
- - - - - - - - -?> - - - - - - - - - - - - - - - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.inc.fixed deleted file mode 100644 index 5b43d8493..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.inc.fixed +++ /dev/null @@ -1,119 +0,0 @@ - - - -<?php echo $title; ?> - - - - - hello - - - - - - - - - - - - - - - - - - - -section as $section) { - ?> -
- - - - - section as $section) { - ?> -
- - - - - - - - - - - - -?> - - - - - - - - - - - - - - - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php index f8cf4cc79..b1aebbd18 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class EmbeddedPhpUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the EmbeddedPhp sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\EmbeddedPhpSniff + */ +final class EmbeddedPhpUnitTest extends AbstractSniffUnitTest { @@ -21,41 +26,199 @@ class EmbeddedPhpUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 7 => 1, - 12 => 1, - 18 => 1, - 19 => 2, - 20 => 1, - 21 => 1, - 22 => 3, - 24 => 1, - 26 => 1, - 29 => 1, - 30 => 1, - 31 => 1, - 34 => 1, - 36 => 1, - 40 => 1, - 41 => 1, - 44 => 1, - 45 => 1, - 49 => 1, - 59 => 1, - 63 => 1, - 93 => 1, - 94 => 2, - 100 => 1, - 102 => 1, - 112 => 1, - 113 => 1, - 116 => 1, - 117 => 1, - ]; + switch ($testFile) { + case 'EmbeddedPhpUnitTest.1.inc': + return [ + 7 => 1, + 12 => 1, + 18 => 1, + 19 => 2, + 20 => 1, + 21 => 1, + 22 => 3, + 24 => 1, + 26 => 1, + 29 => 1, + 30 => 1, + 31 => 1, + 34 => 1, + 36 => 1, + 40 => 1, + 41 => 1, + 44 => 1, + 45 => 1, + 49 => 1, + 59 => 1, + 63 => 1, + 93 => 1, + 94 => 2, + 100 => 1, + 102 => 1, + 112 => 1, + 113 => 1, + 116 => 1, + 117 => 1, + 120 => 1, + 121 => 1, + 128 => 1, + 129 => 1, + 132 => 1, + 134 => 1, + 136 => 1, + 138 => 1, + 142 => 1, + 145 => 1, + 151 => 1, + 158 => 1, + 165 => 1, + 169 => 1, + 175 => 1, + 176 => 2, + 178 => 2, + 179 => 1, + 180 => 2, + 181 => 1, + 189 => 1, + 212 => 1, + 214 => 2, + 219 => 1, + 223 => 1, + 225 => 1, + 226 => 1, + 227 => 2, + 228 => 1, + 235 => 1, + 241 => 1, + 248 => 1, + 253 => 1, + 258 => 1, + 263 => 1, + 264 => 1, + 270 => 1, + 272 => 1, + 276 => 1, + 279 => 2, + 282 => 2, + ]; + + case 'EmbeddedPhpUnitTest.2.inc': + case 'EmbeddedPhpUnitTest.4.inc': + return [ + 5 => 2, + 6 => 2, + 7 => 2, + ]; + + case 'EmbeddedPhpUnitTest.3.inc': + return [ + 10 => 1, + 15 => 1, + 21 => 1, + 22 => 2, + 23 => 1, + 24 => 1, + 25 => 3, + 28 => 1, + 29 => 1, + 30 => 1, + 33 => 1, + 35 => 1, + 39 => 1, + 40 => 1, + 43 => 1, + 44 => 1, + 48 => 1, + 53 => 1, + 55 => 1, + 61 => 1, + 62 => 1, + 65 => 2, + 66 => 2, + 69 => 1, + 70 => 1, + 75 => 1, + 82 => 1, + 89 => 1, + 93 => 1, + 98 => 2, + 99 => 1, + 103 => 2, + 105 => 1, + 111 => 1, + 112 => 2, + 114 => 2, + 115 => 1, + 116 => 2, + 117 => 1, + ]; + + case 'EmbeddedPhpUnitTest.5.inc': + return [ + 16 => 1, + 18 => 1, + 25 => 1, + 26 => 1, + 29 => 1, + 31 => 1, + 33 => 1, + 35 => 1, + 39 => 1, + 42 => 1, + ]; + + case 'EmbeddedPhpUnitTest.12.inc': + case 'EmbeddedPhpUnitTest.13.inc': + return [ + 10 => 1, + 12 => 1, + ]; + + case 'EmbeddedPhpUnitTest.18.inc': + return [11 => 1]; + + case 'EmbeddedPhpUnitTest.19.inc': + return [13 => 1]; + + case 'EmbeddedPhpUnitTest.20.inc': + case 'EmbeddedPhpUnitTest.21.inc': + return [12 => 2]; + + case 'EmbeddedPhpUnitTest.22.inc': + return [ + 14 => 1, + 22 => 1, + ]; + + case 'EmbeddedPhpUnitTest.24.inc': + $shortOpenTagDirective = (bool) ini_get('short_open_tag'); + if ($shortOpenTagDirective === true) { + return [ + 18 => 1, + 20 => 1, + ]; + } + return []; + + case 'EmbeddedPhpUnitTest.25.inc': + if (PHP_VERSION_ID >= 70300) { + return [ + 12 => 2, + 14 => 2, + ]; + } + + // PHP 7.2 or lower: PHP version which doesn't support flexible heredocs/nowdocs yet. + return []; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php index adee78826..db0af7f04 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class EvalUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the Eval sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\EvalSniff + */ +final class EvalUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php index 52f6a00a5..c0c79baa6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class GlobalKeywordUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the GlobalKeyword sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\GlobalKeywordSniff + */ +final class GlobalKeywordUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.1.inc new file mode 100644 index 000000000..d1863c076 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.1.inc @@ -0,0 +1,12 @@ +foo. +Now, I am printing some {$foo->bar[1]}. +This should not print a capital 'A': \x41 +EOT; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.2.inc new file mode 100644 index 000000000..eb0062f08 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.2.inc @@ -0,0 +1,17 @@ + 'a' +<<<<<<< HEAD + 'b' => 'b' +======= + 'c' => 'c' +>>>>>>> master + ); + } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.inc deleted file mode 100644 index 56f4393ae..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.inc +++ /dev/null @@ -1,27 +0,0 @@ -foo. -Now, I am printing some {$foo->bar[1]}. -This should not print a capital 'A': \x41 -EOT; - -// The following function has a simulated git conflict for testing. -// This is not a merge conflict - it is a valid test case. -// Please do not remove. -function test() - { - $arr = array( - 'a' => 'a' -<<<<<<< HEAD - 'b' => 'b' -======= - 'c' => 'c' ->>>>>>> master - ); - } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php index 2f06f0b08..5d78d8938 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class HeredocUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the Heredoc sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\HeredocSniff + */ +final class HeredocUnitTest extends AbstractSniffUnitTest { @@ -21,14 +26,22 @@ class HeredocUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 2 => 1, - 8 => 1, - ]; + switch ($testFile) { + case 'HeredocUnitTest.1.inc': + return [ + 2 => 1, + 8 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc index dd851461b..d16c7f2eb 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc @@ -48,3 +48,40 @@ new class { } } }; + +$outerClosure = function () +{ + // Functions inside closures are not allowed. + function innerFunction() { + } +}; + +// Allow methods in classes/traits/interfaces defined inside functions +function foo() { + if (class_exists('MyClass') === false) { + class MyClass { + function foo() {} + } + } + + if (trait_exists('MyTrait') === false) { + trait MyTrait { + function foo() {} + } + } + + if (interface_exists('MyInterface') === false) { + interface MyInterface { + function foo(); + } + } + + // But disallow functions nested inside those methods + if (class_exists('NestedFunctionInMethod') === false) { + class NestedFunctionInMethod { + function foo() { + function innerFunction() {} + } + } + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php index 3c9ad07bd..fff8871e6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class InnerFunctionsUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the InnerFunctions sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\InnerFunctionsSniff + */ +final class InnerFunctionsUnitTest extends AbstractSniffUnitTest { @@ -28,6 +33,8 @@ public function getErrorList() return [ 5 => 1, 46 => 1, + 55 => 1, + 83 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc index c67381ad8..702b13de0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc @@ -41,3 +41,10 @@ $callToNamespacedFunction = namespace\STR_REPEAT($a, 2); // Could potentially be $filePath = new \File($path); $count = $object?->Count(); + +class AttributesShouldBeIgnored +{ + #[Putenv('FOO', 'foo')] + public function foo(): void + {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed index 40507c040..281425c59 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed @@ -41,3 +41,10 @@ $callToNamespacedFunction = namespace\STR_REPEAT($a, 2); // Could potentially be $filePath = new \File($path); $count = $object?->Count(); + +class AttributesShouldBeIgnored +{ + #[Putenv('FOO', 'foo')] + public function foo(): void + {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php index 708d01ef0..5feb363f6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class LowercasePHPFunctionsUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the LowercasePHPFunctions sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\LowercasePHPFunctionsSniff + */ +final class LowercasePHPFunctionsUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc index ed7f01151..4b1d1ca65 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc @@ -297,5 +297,124 @@ class TestAlternativeControlStructures { $var_after_class_in_global_space = 1; do_something_else(); -// Intentional syntax error. -return array_map( +// These are parse errors, but that's not the concern of the sniff. +function parseError1() { + defined('FOO') or return 'foo'; + echo 'unreachable'; +} + +function parseError2() { + defined('FOO') || continue; + echo 'unreachable'; +} + +// All logical operators are allowed with inline expressions (but this was not correctly handled by the sniff). +function exitExpressionsWithLogicalOperators() { + $condition = false; + $condition || exit(); + $condition or die(); + + $condition = true; + $condition && die(); + $condition and exit; + + $condition xor die(); + + echo 'still executable as exit, in all of the above cases, is used as part of an expression'; +} + +// Inline expressions are allowed in ternaries. +function exitExpressionsInTernary() { + $value = $myValue ? $myValue : exit(); + $value = $myValue ?: exit(); + $value = $var == 'foo' ? 'bar' : die( 'world' ); + + $value = (!$myValue ) ? exit() : $myValue; + $value = $var != 'foo' ? die( 'world' ) : 'bar'; + + echo 'still executable'; +} + +// Inline expressions are allowed with null coalesce and null coalesce equals. +function exitExpressionsWithNullCoalesce() { + $value = $nullableValue ?? exit(); + $value ??= die(); + echo 'still executable'; +} + +// Inline expressions are allowed in arrow functions. +function exitExpressionsInArrowFunction() { + $callable = fn() => die(); + echo 'still executable'; +} + +// PHP 8.0+: throw expressions which don't stop execution. +function nonStoppingThrowExpressions() { + $callable = fn() => throw new Exception(); + + $value = $myValue ? 'something' : throw new Exception(); + $value = $myValue ?: throw new Exception(); + $value = $myValue ? throw new Exception() : 'something'; + + $value = $nullableValue ?? throw new Exception(); + $value ??= throw new Exception(); + + $condition && throw new Exception(); + $condition || throw new Exception(); + $condition and throw new Exception(); + $condition or throw new Exception(); + + echo 'still executable as throw, in all of the above cases, is used as part of an expression'; + + throw new Exception(); + echo 'non-executable'; +} + +// PHP 8.0+: throw expressions which do stop execution. +function executionStoppingThrowExpressionsA() { + $condition xor throw new Exception(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsB() { + throw $userIsAuthorized ? new ForbiddenException() : new UnauthorizedException(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsC() { + throw $condition1 && $condition2 ? new Exception1() : new Exception2(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsD() { + throw $exception ??= new Exception(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsE() { + throw $maybeNullException ?? new Exception(); + echo 'non-executable'; +} + +function returnNotRequiredIgnoreCommentsA() +{ + if ($something === TRUE) { + return /*comment*/; + } + + echo 'foo'; + return /*comment*/; +} + +function returnNotRequiredIgnoreCommentsB() +{ + echo 'foo'; + return; + /*comment*/ +} + +$closure = function () +{ + echo 'foo'; + return; // This return should be flagged as not required. +}; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc index c9bf052f3..9b7a22bcc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc @@ -58,4 +58,16 @@ $a = new class { } }; +// Multiple statements are still one line of unreachable code, so should get +// only one complaint from this sniff. (Well, technically two here since there +// are two 'exit()' statements above, so one complaint from each of those. So, +// two here, but not six.) +echo 'one'; echo 'two'; echo 'three'; + +// A single statement split across multiple lines. Here we get complaints for +// each line, even though they're all part of one statement. +echo 'one' . 'two' + . 'three' . 'four' + . 'five' . 'six'; + interface MyInterface { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.3.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.3.inc new file mode 100644 index 000000000..6fe5c16c6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.3.inc @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
non-executable
+ + + + + + + + +
non-executable
+ + + + + + + + +
non-executable
+ + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.4.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.4.inc new file mode 100644 index 000000000..189466b4d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.4.inc @@ -0,0 +1,6 @@ + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class NonExecutableCodeUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the NonExecutableCode sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\NonExecutableCodeSniff + */ +final class NonExecutableCodeUnitTest extends AbstractSniffUnitTest { @@ -74,8 +79,19 @@ public function getWarningList($testFile='') 252 => 1, 253 => 1, 254 => 2, + 303 => 1, + 308 => 1, + 370 => 1, + 376 => 1, + 381 => 1, + 386 => 1, + 391 => 1, + 396 => 1, + 406 => 1, + 412 => 1, + 419 => 1, ]; - break; + case 'NonExecutableCodeUnitTest.2.inc': return [ 7 => 1, @@ -84,11 +100,22 @@ public function getWarningList($testFile='') 10 => 2, 14 => 1, 54 => 2, + 65 => 2, + 69 => 2, + 70 => 2, + 71 => 2, + ]; + + case 'NonExecutableCodeUnitTest.3.inc': + return [ + 27 => 1, + 36 => 1, + 45 => 1, + 54 => 1, + 62 => 1, ]; - break; default: return []; - break; }//end switch }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc index 6df12cca4..0a1554ec8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc @@ -70,3 +70,7 @@ class MyClass { interface Base { protected $anonymous; } + +class PHP84FinalProperties { + final int $final; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php index 59e49910d..309d02983 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Scope; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class MemberVarScopeUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the MemberVarScope sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\MemberVarScopeSniff + */ +final class MemberVarScopeUnitTest extends AbstractSniffUnitTest { @@ -34,6 +39,7 @@ public function getErrorList() 41 => 1, 66 => 2, 67 => 1, + 75 => 1, ]; }//end getErrorList() @@ -49,6 +55,7 @@ public function getErrorList() */ public function getWarningList() { + // Warning from getMemberProperties() about parse error. return [71 => 1]; }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php index 4dc717795..d57ce9d9b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Scope; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class MethodScopeUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the MethodScope sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\MethodScopeSniff + */ +final class MethodScopeUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php index b1a5dd6af..543b56973 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Scope; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class StaticThisUsageUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the StaticThisUsage sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\StaticThisUsageSniff + */ +final class StaticThisUsageUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php index 862af7d20..e59da3c6e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Strings; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ConcatenationSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ConcatenationSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Strings\ConcatenationSpacingSniff + */ +final class ConcatenationSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php index a95d1888b..df50beee1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Strings; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class DoubleQuoteUsageUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the DoubleQuoteUsage sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Strings\DoubleQuoteUsageSniff + */ +final class DoubleQuoteUsageUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php index 0d9af1e93..dd8ead06a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Strings; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class EchoedStringsUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the EchoedStrings sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Strings\EchoedStringsSniff + */ +final class EchoedStringsUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php index 48bc841fd..38dba6d42 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class CastSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the CastSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\CastSpacingSniff + */ +final class CastSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php index ac3f5d6ff..c5567cb72 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ControlStructureSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ControlStructureSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ControlStructureSpacingSniff + */ +final class ControlStructureSpacingUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class ControlStructureSpacingUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='ControlStructureSpacingUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'ControlStructureSpacingUnitTest.inc': @@ -61,7 +66,7 @@ public function getErrorList($testFile='ControlStructureSpacingUnitTest.inc') 261 => 1, 262 => 1, ]; - break; + case 'ControlStructureSpacingUnitTest.js': return [ 3 => 1, @@ -76,10 +81,9 @@ public function getErrorList($testFile='ControlStructureSpacingUnitTest.inc') 74 => 2, 75 => 2, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc index e831e257d..8c8daf1f4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc @@ -37,3 +37,54 @@ function foo() } + +// Nested functions - okay. +function hasNestedOkay() { + function nestedFunction() { + echo 'hello'; + } + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; + } + +}; + +mycallback( + 'name', + function() { + echo 'hello'; + } + +); + +// Nested functions - not okay. +function hasNestedNotOkay() { + function nestedFunction() {} + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; } + +}; + +mycallback('name', function() { + echo 'hello'; + + + + } + +); + +mycallback('name', function() { + // Comment + + } + +); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed index c567dbb2d..1166366f4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed @@ -43,3 +43,52 @@ function foo() }//end for } + +// Nested functions - okay. +function hasNestedOkay() { + function nestedFunction() { + echo 'hello'; + } + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; + } + +}; + +mycallback( + 'name', + function() { + echo 'hello'; + } + +); + +// Nested functions - not okay. +function hasNestedNotOkay() { + function nestedFunction() { +} + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; +} + +}; + +mycallback('name', function() { + echo 'hello'; + } + +); + +mycallback('name', function() { + // Comment + } + +); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php index 2e18f875b..7361cf499 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class FunctionClosingBraceSpaceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the FunctionClosingBraceSpace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\FunctionClosingBraceSpaceSniff + */ +final class FunctionClosingBraceSpaceUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class FunctionClosingBraceSpaceUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='FunctionClosingBraceSpaceUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'FunctionClosingBraceSpaceUnitTest.inc': @@ -36,8 +41,12 @@ public function getErrorList($testFile='FunctionClosingBraceSpaceUnitTest.inc') 29 => 1, 31 => 1, 39 => 1, + 66 => 1, + 72 => 1, + 81 => 1, + 88 => 1, ]; - break; + case 'FunctionClosingBraceSpaceUnitTest.js': return [ 13 => 1, @@ -49,10 +58,9 @@ public function getErrorList($testFile='FunctionClosingBraceSpaceUnitTest.inc') 84 => 1, 128 => 1, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php index 438263ebe..dcfb3dd17 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class FunctionOpeningBraceSpaceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the FunctionOpeningBraceSpace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\FunctionOpeningBraceSpaceSniff + */ +final class FunctionOpeningBraceSpaceUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class FunctionOpeningBraceSpaceUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='FunctionOpeningBraceSpaceUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'FunctionOpeningBraceSpaceUnitTest.inc': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc index 36a287f07..83600e873 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc @@ -574,3 +574,179 @@ class ClassWithAttributes { // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacing 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +// Issue #3904. +echo 'this line belongs with the #3904 test'; +class Person {public function __construct($name){}} +echo 'this line belongs with the #3904 test'; + +function Foo() {} function bar($name){} +echo 'this line belongs with the #3904 test'; + + +/** + * foo. + */ +function a() { +}/** + * foo. + */ +function b() { +} + + +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 1 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 0 + +class DocblockFollowedByAttributesCorrectSpacing { + + /** + * No error. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooMuchSpacing { + + + + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooLittleSpacing { + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesCorrectSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * No error. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooMuchSpacing { + + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooLittleSpacing { + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +// Reset properties to their default value. +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +class SilenceBeforeErrorIfPreviousThingWasAFunctionBug +{ + /** + * Docblock. + */ + + #[ReturnTypeWillChange] + + + + + + #[ + + AnotherAttribute + + ]#[AndAThirdAsWell] + + public function blankLineDetectionA() + { + + }//end blankLineDetectionA() + + /** + * Docblock. + */ + #[ReturnTypeWillChange] + + public function blankLineDetectionB() + { + + }//end blankLineDetectionB() +}//end class + +// Issue #945. +class OnlyAcceptFirstDocblockAsBelongingWithFunction { + /** + * Superfluous docblock + */ + + + /** + * Function docblock + */ + function correctSpacing($x) {} + + + /** + * Superfluous docblock + */ + /** + * Function docblock + */ + function incorrectSpacing($x) {} + + +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed index ac2df1cb7..91444e7ca 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed @@ -656,3 +656,195 @@ class ClassWithAttributes { // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacing 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +// Issue #3904. +echo 'this line belongs with the #3904 test'; + + +class Person {public function __construct($name){}} + + +echo 'this line belongs with the #3904 test'; + + +function Foo() {} function bar($name){} + + +echo 'this line belongs with the #3904 test'; + + +/** + * foo. + */ +function a() { +} + + +/** + * foo. + */ +function b() { +} + + +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 1 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 0 + +class DocblockFollowedByAttributesCorrectSpacing { + + /** + * No error. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooMuchSpacing { + + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooLittleSpacing { + + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesCorrectSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * No error. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooMuchSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooLittleSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +// Reset properties to their default value. +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +class SilenceBeforeErrorIfPreviousThingWasAFunctionBug +{ + + + /** + * Docblock. + */ + + #[ReturnTypeWillChange] + + + + + + #[ + + AnotherAttribute + + ]#[AndAThirdAsWell] + + public function blankLineDetectionA() + { + + }//end blankLineDetectionA() + + + /** + * Docblock. + */ + #[ReturnTypeWillChange] + + public function blankLineDetectionB() + { + + }//end blankLineDetectionB() + + +}//end class + +// Issue #945. +class OnlyAcceptFirstDocblockAsBelongingWithFunction { + /** + * Superfluous docblock + */ + + + /** + * Function docblock + */ + function correctSpacing($x) {} + + + /** + * Superfluous docblock + */ + + + /** + * Function docblock + */ + function incorrectSpacing($x) {} + + +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php index fabb6adb9..a963a9a4b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class FunctionSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the FunctionSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\FunctionSpacingSniff + */ +final class FunctionSpacingUnitTest extends AbstractSniffUnitTest { @@ -95,6 +100,17 @@ public function getErrorList($testFile='') 553 => 1, 560 => 1, 566 => 1, + 580 => 2, + 583 => 4, + 591 => 1, + 627 => 1, + 641 => 1, + 672 => 1, + 686 => 1, + 714 => 1, + 717 => 1, + 727 => 1, + 749 => 1, ]; case 'FunctionSpacingUnitTest.2.inc': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php index 46b0d858f..f5d6c61f7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class LanguageConstructSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the LanguageConstructSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\LanguageConstructSpacingSniff + */ +final class LanguageConstructSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php index 62b74e369..31158fd27 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class LogicalOperatorSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the LogicalOperatorSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\LogicalOperatorSpacingSniff + */ +final class LogicalOperatorSpacingUnitTest extends AbstractSniffUnitTest { @@ -21,11 +26,9 @@ class LogicalOperatorSpacingUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * - * @param string $testFile The name of the file being tested. - * * @return array */ - public function getErrorList($testFile='LogicalOperatorSpacingUnitTest.inc') + public function getErrorList() { return [ 4 => 2, diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc new file mode 100644 index 000000000..efb2f2c33 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc @@ -0,0 +1,446 @@ + 'a', 'b' => 'b' ), + $varQ = 'string', + $varR = 123; +} + +// Make sure the determination of whether a property is the first property or not is done correctly. +class ClassUsingSimpleTraits +{ + use HelloWorld; + + + /* comment */ + public $firstVar = array( 'a', 'b' ); + protected $secondVar = true; +} + +class ClassUsingComplexTraits +{ + use A, B { + B::smallTalk insteadof A; + A::bigTalk insteadof B; + } + + + + public $firstVar = array( 'a', 'b' ); + + + /* comment */ + protected $secondVar = true; +} + +class Foo +{ + + + private function foo() + { + } + + + /* no error here because after function */ + private $bar = false; +} + +class CommentedOutCodeAtStartOfClass { + + /** + * Description. + * + * @var bool + */ + //public $commented_out_property = true; + + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class CommentedOutCodeAtStartOfClassNoBlankLine { + + // phpcs:disable Stnd.Cat.Sniff -- For reasons. + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class HasAttributes +{ + /** + * Short description of the member variable. + * + * @var array + */ + + #[ORM\Id]#[ORM\Column("integer")] + + private $id; + + + /** + * Short description of the member variable. + * + * @var array + */ + #[ORM\GeneratedValue] + + #[ORM\Column(ORM\Column::T_INTEGER)] + protected $height; + + #[SingleAttribute] + protected $propertySingle; + + #[FirstAttribute] + #[SecondAttribute] + protected $propertyDouble; + #[ThirdAttribute] + protected $propertyWithoutSpacing; +} + +enum SomeEnum +{ + // Enum cannot have properties + + case ONE = 'one'; +} + +class SupportReadonlyProperties { + readonly int $readonlyA; + public readonly string $publicReadonly; + readonly bool $readonlyB; + readonly private bool $readonlyPrivate; +} + +class NoPreambleMultilineDeclaration { + public + static + int $prop = 1; +} + +class MultipleBlankLinesInPreAmble { + + /** + * Docblock. + */ + + #[MyAttribute] + + + #[ + + BlankLinesWithinAnAttributeShouldBeLeftAlone + + ] + + public $prop; +} + +final class BlankLinesBetweenVsAttributesWithoutCommentIssueSquiz3594 +{ + + // PHPCS can fix blank lines for the first property, but not for the second. (fixed now) + #[SingleAttribute] + + public $property1; + #[SingleAttribute] + + public $property2; +} + +class PHP84FinalProperties { + final int $finalA; + + /** + * Docblock + */ + public final string $publicfinal; + #[AnAttribute] + final bool $finalB; + + final private bool $finalPrivate; +} + +class MultilineCommentShouldNotBeSplitUp { + // This is the first line + // of a multi-line comment + // which should be recognized as belonging + // with the property. + public $prop; + + + /* This is the first line + of a multi-line comment + which should be recognized as belonging + with the property. + */ + public $prop; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed new file mode 100644 index 000000000..e93746517 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed @@ -0,0 +1,433 @@ + 'a', 'b' => 'b' ), + $varQ = 'string', + $varR = 123; +} + +// Make sure the determination of whether a property is the first property or not is done correctly. +class ClassUsingSimpleTraits +{ + use HelloWorld; + + /* comment */ + public $firstVar = array( 'a', 'b' ); + + protected $secondVar = true; +} + +class ClassUsingComplexTraits +{ + use A, B { + B::smallTalk insteadof A; + A::bigTalk insteadof B; + } + + public $firstVar = array( 'a', 'b' ); + + /* comment */ + protected $secondVar = true; +} + +class Foo +{ + + + private function foo() + { + } + + + /* no error here because after function */ + private $bar = false; +} + +class CommentedOutCodeAtStartOfClass { + + /** + * Description. + * + * @var bool + */ + //public $commented_out_property = true; + + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class CommentedOutCodeAtStartOfClassNoBlankLine { + + // phpcs:disable Stnd.Cat.Sniff -- For reasons. + + /** + * Description. + * + * @var bool + */ + public $property = true; +} + +class HasAttributes +{ + + /** + * Short description of the member variable. + * + * @var array + */ + #[ORM\Id]#[ORM\Column("integer")] + private $id; + + /** + * Short description of the member variable. + * + * @var array + */ + #[ORM\GeneratedValue] + #[ORM\Column(ORM\Column::T_INTEGER)] + protected $height; + + #[SingleAttribute] + protected $propertySingle; + + #[FirstAttribute] + #[SecondAttribute] + protected $propertyDouble; + + #[ThirdAttribute] + protected $propertyWithoutSpacing; +} + +enum SomeEnum +{ + // Enum cannot have properties + + case ONE = 'one'; +} + +class SupportReadonlyProperties { + + readonly int $readonlyA; + + public readonly string $publicReadonly; + + readonly bool $readonlyB; + + readonly private bool $readonlyPrivate; +} + +class NoPreambleMultilineDeclaration { + + public + static + int $prop = 1; +} + +class MultipleBlankLinesInPreAmble { + + /** + * Docblock. + */ + #[MyAttribute] + #[ + + BlankLinesWithinAnAttributeShouldBeLeftAlone + + ] + public $prop; +} + +final class BlankLinesBetweenVsAttributesWithoutCommentIssueSquiz3594 +{ + + // PHPCS can fix blank lines for the first property, but not for the second. (fixed now) + #[SingleAttribute] + public $property1; + + #[SingleAttribute] + public $property2; +} + +class PHP84FinalProperties { + + final int $finalA; + + /** + * Docblock + */ + public final string $publicfinal; + + #[AnAttribute] + final bool $finalB; + + final private bool $finalPrivate; +} + +class MultilineCommentShouldNotBeSplitUp { + + // This is the first line + // of a multi-line comment + // which should be recognized as belonging + // with the property. + public $prop; + + /* This is the first line + of a multi-line comment + which should be recognized as belonging + with the property. + */ + public $prop; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc new file mode 100644 index 000000000..2aab7c059 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc @@ -0,0 +1,10 @@ + 'a', 'b' => 'b' ), - $varQ = 'string', - $varR = 123; -} - -// Make sure the determination of whether a property is the first property or not is done correctly. -class ClassUsingSimpleTraits -{ - use HelloWorld; - - - /* comment */ - public $firstVar = array( 'a', 'b' ); - protected $secondVar = true; -} - -class ClassUsingComplexTraits -{ - use A, B { - B::smallTalk insteadof A; - A::bigTalk insteadof B; - } - - - - public $firstVar = array( 'a', 'b' ); - - - /* comment */ - protected $secondVar = true; -} - -class Foo -{ - - - private function foo() - { - } - - - /* no error here because after function */ - private $bar = false; -} - -class CommentedOutCodeAtStartOfClass { - - /** - * Description. - * - * @var bool - */ - //public $commented_out_property = true; - - /** - * Description. - * - * @var bool - */ - public $property = true; -} - -class CommentedOutCodeAtStartOfClassNoBlankLine { - - // phpcs:disable Stnd.Cat.Sniff -- For reasons. - /** - * Description. - * - * @var bool - */ - public $property = true; -} - -class HasAttributes -{ - /** - * Short description of the member variable. - * - * @var array - */ - - #[ORM\Id]#[ORM\Column("integer")] - - private $id; - - - /** - * Short description of the member variable. - * - * @var array - */ - #[ORM\GeneratedValue] - - #[ORM\Column(ORM\Column::T_INTEGER)] - protected $height; - - #[SingleAttribute] - protected $propertySingle; - - #[FirstAttribute] - #[SecondAttribute] - protected $propertyDouble; - #[ThirdAttribute] - protected $propertyWithoutSpacing; -} - -enum SomeEnum -{ - // Enum cannot have properties - - case ONE = 'one'; -} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc.fixed deleted file mode 100644 index d683eaadf..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc.fixed +++ /dev/null @@ -1,359 +0,0 @@ - 'a', 'b' => 'b' ), - $varQ = 'string', - $varR = 123; -} - -// Make sure the determination of whether a property is the first property or not is done correctly. -class ClassUsingSimpleTraits -{ - use HelloWorld; - - /* comment */ - public $firstVar = array( 'a', 'b' ); - - protected $secondVar = true; -} - -class ClassUsingComplexTraits -{ - use A, B { - B::smallTalk insteadof A; - A::bigTalk insteadof B; - } - - public $firstVar = array( 'a', 'b' ); - - /* comment */ - protected $secondVar = true; -} - -class Foo -{ - - - private function foo() - { - } - - - /* no error here because after function */ - private $bar = false; -} - -class CommentedOutCodeAtStartOfClass { - - /** - * Description. - * - * @var bool - */ - //public $commented_out_property = true; - - /** - * Description. - * - * @var bool - */ - public $property = true; -} - -class CommentedOutCodeAtStartOfClassNoBlankLine { - - // phpcs:disable Stnd.Cat.Sniff -- For reasons. - - /** - * Description. - * - * @var bool - */ - public $property = true; -} - -class HasAttributes -{ - - /** - * Short description of the member variable. - * - * @var array - */ - #[ORM\Id]#[ORM\Column("integer")] - private $id; - - /** - * Short description of the member variable. - * - * @var array - */ - #[ORM\GeneratedValue] - #[ORM\Column(ORM\Column::T_INTEGER)] - protected $height; - - #[SingleAttribute] - protected $propertySingle; - - #[FirstAttribute] - #[SecondAttribute] - protected $propertyDouble; - - #[ThirdAttribute] - protected $propertyWithoutSpacing; -} - -enum SomeEnum -{ - // Enum cannot have properties - - case ONE = 'one'; -} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php index 9b4066811..9f4336256 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class MemberVarSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the MemberVarSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\MemberVarSpacingSniff + */ +final class MemberVarSpacingUnitTest extends AbstractSniffUnitTest { @@ -21,48 +26,72 @@ class MemberVarSpacingUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 4 => 1, - 7 => 1, - 20 => 1, - 30 => 1, - 35 => 1, - 44 => 1, - 50 => 1, - 73 => 1, - 86 => 1, - 106 => 1, - 115 => 1, - 150 => 1, - 160 => 1, - 165 => 1, - 177 => 1, - 186 => 1, - 200 => 1, - 209 => 1, - 211 => 1, - 224 => 1, - 229 => 1, - 241 => 1, - 246 => 1, - 252 => 1, - 254 => 1, - 261 => 1, - 275 => 1, - 276 => 1, - 288 => 1, - 292 => 1, - 333 => 1, - 342 => 1, - 346 => 1, - 353 => 1, - 357 => 1, - 366 => 1, - ]; + switch ($testFile) { + case 'MemberVarSpacingUnitTest.1.inc': + return [ + 4 => 1, + 7 => 1, + 20 => 1, + 30 => 1, + 35 => 1, + 44 => 1, + 50 => 1, + 73 => 1, + 86 => 1, + 107 => 1, + 115 => 1, + 151 => 1, + 160 => 1, + 165 => 1, + 177 => 1, + 186 => 1, + 200 => 1, + 209 => 1, + 211 => 1, + 224 => 1, + 229 => 1, + 241 => 1, + 246 => 1, + 252 => 1, + 254 => 1, + 261 => 1, + 275 => 1, + 276 => 1, + 288 => 1, + 292 => 1, + 333 => 1, + 343 => 1, + 345 => 1, + 346 => 1, + 355 => 1, + 357 => 1, + 366 => 1, + 377 => 1, + 378 => 1, + 379 => 1, + 380 => 1, + 384 => 1, + 394 => 1, + 396 => 1, + 403 => 1, + 412 => 1, + 415 => 1, + 416 => 1, + 420 => 1, + 427 => 1, + 437 => 1, + 445 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php index 82a4056f7..c1ef24a42 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ObjectOperatorSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ObjectOperatorSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ObjectOperatorSpacingSniff + */ +final class ObjectOperatorSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc new file mode 100644 index 000000000..29acf308a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc @@ -0,0 +1,510 @@ + $j && $k< $l && $m>= $n && $o<= $p && $q<> $r; + +$a ==$b && $c !=$d && $e ===$f && $g !==$h; +$i >$j && $k <$l && $m >=$n && $o <=$p && $q <>$r; + +function myFunction($variable=0, $var2='string') {} + +if (index > -1) { +} + +array_walk_recursive($array, function(&$item) use (&$something) { +}); + +$var = saveFile(&$model, &$foo); + +// This is all valid. +$boo = -$foo; +function foo($boo = -1) {} +$foo = array('boo' => -1); +$x = $test ? -1 : 1; +$y = $test ? 1 : -1; +$z = $test ?: false; + +$closureWithDefaultParameter = function (array $testArray=array()) {}; + +switch ($foo) { + case -1: + break; +} + +$y = 1 * -1; +$y = -1 * 1; +$y = -1 * $var; +$y = 10 / -2; +$y = -10 / 2; +$y = (-10 / 2); +$y = (-10 / $var); +$y = 10 + -2; +$y = -10 + 2; + +$a = $x?$y:$z; +$a = $x ? $y : $z; + +$y = 1 + + 2 + - 3; + +$y = 1 + + 2 - + 3; + +$y = 1 ++ 2 +- 3; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true +$y = 1 + + 2 + - 3; + +$y = 1 + + 2 - + 3; + +$y = 1 ++ 2 +- 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false + +if (true || -1 == $b) { +} + +$var = array(-1); +$var = [-1]; +$var = [0, -1, -2]; + +$y = array(&$x); +$y = [&$x]; +$y = array(&$a, &$b, &$c); +$y = [&$a, &$b, &$c]; +$y = array(&$a => 1, 2 => &$b, &$c); +$y = [&$a => 1, 2 => &$b, &$c]; + +if ($a <=> $b) { +} + +if ($a <=>$b) { +} + +$a |= $b; +$a **= $b; +$a ??= $b; + +$a = +1; + +function bar($boo = +1) {} + +$username = $_GET['user']??'nobody'; + +function foo(string $bar, array $baz, ?MyClass $object) : MyClass {} + +declare(strict_types=1); + +function foo($c = ((BAR)?10:100)) {} + +$res = $a ?: $b; +$res = $a ?: $b; +$res = $a ?: $b; +$res = $a ?: $b; + +$res = $a ? : $b; +$res = $a ? : $b; +$res = $a ? : $b; +$res = $a ? : $b; + +function foo(string $a = '', ?string $b = ''): ?string {} + +// Issue #1605. +$text = preg_replace_callback( + self::CHAR_REFS_REGEX, + [ 'Sanitizer', 'decodeCharReferencesCallback' ], + $text, /* limit */ -1, $count ); + +if (true || /* test */ -1 == $b) {} +$y = 10 + /* test */ -2; + +// Issue #1604. +Hooks::run( 'ParserOptionsRegister', [ + &self::$defaults, + &self::$inCacheKey, + &self::$lazyOptions, +] ); + +$x = $foo ? function (): int { + return 1; +} : $bar; + +$x = $foo ? function ($foo) + // comment + : int { + return 1; +} : $bar; + +$x = $foo ? function ($foo) use /* comment */ ($bar): int { + return 1; +} : $bar; + +$x = !$foo ? $bar : function (): int { + return 1; +}; + +$a = + // Comment. + [ + 'a', + 'b', + ]; + +$a = +// phpcs:ignore Standard.Category.Sniff -- for reasons. +[ + 'a', + 'b', +]; + +$foo = is_array($bar) ? array_map( + function () {}, + $bar + ) : $bar; + +function bar(): array {} + +if ($line{-1} === ':') { + $line = substr($line, 0, -1); +} + +$a = $a instanceof $b; +$a = $a instanceof $b; +$a = ($a)instanceof$b; + +fn&($x) => $x; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false +$a = 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true +yield -1; +echo -1; +$a = -1; +func(-1); +$a = [-1]; +return -1; +print -1; +$a &= -1; +switch ($a) { + case -1: +} +$a = $a ?? -1; +$a .= -1; +$a /= -1; +$a = [1 => -1]; +$a = $a == -1; +$a = $a >= -1; +$a = $a === -1; +$a = $a != -1; +$a = $a !== -1; +$a = $a <= -1; +$a = $a <=> -1; +$a = $a and -1; +$a = $a or -1; +$a = $a xor -1; +$a -= -1; +$a %= -1; +$a *= -1; +$a |= -1; +$a += -1; +$a = $a ** -1; +$a **= -1; +$a = $a << -1; +$a <<= -1; +$a = $a >> -1; +$a >>= -1; +$a = (string) -1; +$a = (array) -1; +$a = (bool) -1; +$a = (object) -1; +$a = (unset) -1; +$a = (float) -1; +$a = (int) -1; +$a ^= -1; +$a = [$a, -1]; +$a = $a[-1]; +$a = $a ? -1 : -1; + +yield - 1; +echo - 1; +$a = - 1; +func(- 1); +$a = [- 1]; +return - 1; +print - 1; +$a &= - 1; +switch ($a) { + case - 1: +} +$a = $a ?? - 1; +$a .= - 1; +$a /= - 1; +$a = [1 => - 1]; +$a = $a == - 1; +$a = $a >= - 1; +$a = $a === - 1; +$a = $a != - 1; +$a = $a !== - 1; +$a = $a <= - 1; +$a = $a <=> - 1; +$a = $a and - 1; +$a = $a or - 1; +$a = $a xor - 1; +$a -= - 1; +$a %= - 1; +$a *= - 1; +$a |= - 1; +$a += - 1; +$a = $a ** - 1; +$a **= - 1; +$a = $a << - 1; +$a <<= - 1; +$a = $a >> - 1; +$a >>= - 1; +$a = (string) - 1; +$a = (array) - 1; +$a = (bool) - 1; +$a = (object) - 1; +$a = (unset) - 1; +$a = (float) - 1; +$a = (int) - 1; +$a ^= - 1; +$a = [$a, - 1]; +$a = $a[- 1]; +$a = $a ? - 1 : - 1; + + +yield -$b; +echo -$b; +$a = -$b; +func(-$b); +$a = [-$b]; +return -$b; +print -$b; +$a &= -$b; +switch ($a) { + case -$b: +} +$a = $a ?? -$b; +$a .= -$b; +$a /= -$b; +$a = [1 => -$b]; +$a = $a == -$b; +$a = $a >= -$b; +$a = $a === -$b; +$a = $a != -$b; +$a = $a !== -$b; +$a = $a <= -$b; +$a = $a <=> -$b; +$a = $a and -$b; +$a = $a or -$b; +$a = $a xor -$b; +$a -= -$b; +$a %= -$b; +$a *= -$b; +$a |= -$b; +$a += -$b; +$a = $a ** -$b; +$a **= -$b; +$a = $a << -$b; +$a <<= -$b; +$a = $a >> -$b; +$a >>= -$b; +$a = (string) -$b; +$a = (array) -$b; +$a = (bool) -$b; +$a = (object) -$b; +$a = (unset) -$b; +$a = (float) -$b; +$a = (int) -$b; +$a ^= -$b; +$a = [$a, -$b]; +$a = $a[-$b]; +$a = $a ? -$b : -$b; + +yield - $b; +echo - $b; +$a = - $b; +func(- $b); +$a = [- $b]; +return - $b; +print - $b; +$a &= - $b; +switch ($a) { + case - $b: +} +$a = $a ?? - $b; +$a .= - $b; +$a /= - $b; +$a = [1 => - $b]; +$a = $a == - $b; +$a = $a >= - $b; +$a = $a === - $b; +$a = $a != - $b; +$a = $a !== - $b; +$a = $a <= - $b; +$a = $a <=> - $b; +$a = $a and - $b; +$a = $a or - $b; +$a = $a xor - $b; +$a -= - $b; +$a %= - $b; +$a *= - $b; +$a |= - $b; +$a += - $b; +$a = $a ** - $b; +$a **= - $b; +$a = $a << - $b; +$a <<= - $b; +$a = $a >> - $b; +$a >>= - $b; +$a = (string) - $b; +$a = (array) - $b; +$a = (bool) - $b; +$a = (object) - $b; +$a = (unset) - $b; +$a = (float) - $b; +$a = (int) - $b; +$a ^= - $b; +$a = [$a, - $b]; +$a = $a[- $b]; +$a = $a ? - $b : - $b; + +exit -1; + +$cl = function ($boo =-1) {}; +$cl = function ($boo =+1) {}; +$fn = fn ($boo =-1) => $boo; +$fn = fn ($boo =+1) => $boo; + +$fn = static fn(DateTime $a, DateTime $b): int => -($a->getTimestamp() <=> $b->getTimestamp()); + +$a = 'a '.-MY_CONSTANT; +$a = 'a '.-$b; +$a = 'a '.- MY_CONSTANT; +$a = 'a '.- $b; + +match ($a) { + 'a' => -1, + 'b', 'c', 'd' => -2, + default => -3, +}; + +$foo = $var + ? 10 + : true; + +// Safeguard that a non-fixable error is thrown when there is a new line before the operator, +// but the last non-whitespace token before the operator is a comment token. +$foo = $var // Comment + ? false /* Comment */ + : true; + +$foo = $var // phpcs: ignore Stnd.Cat.Sniff -- for reasons. + + + ? $something /** + * Don't ask, but someone might have a docblock between the lines. It's valid PHP after all. + */ + + + : true; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true +$foo = $var // Comment + ? false // Comment + : true; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed new file mode 100644 index 000000000..5c94e3658 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed @@ -0,0 +1,502 @@ + $j && $k < $l && $m >= $n && $o <= $p && $q <> $r; + +$a == $b && $c != $d && $e === $f && $g !== $h; +$i > $j && $k < $l && $m >= $n && $o <= $p && $q <> $r; + +function myFunction($variable=0, $var2='string') {} + +if (index > -1) { +} + +array_walk_recursive($array, function(&$item) use (&$something) { +}); + +$var = saveFile(&$model, &$foo); + +// This is all valid. +$boo = -$foo; +function foo($boo = -1) {} +$foo = array('boo' => -1); +$x = $test ? -1 : 1; +$y = $test ? 1 : -1; +$z = $test ?: false; + +$closureWithDefaultParameter = function (array $testArray=array()) {}; + +switch ($foo) { + case -1: + break; +} + +$y = 1 * -1; +$y = -1 * 1; +$y = -1 * $var; +$y = 10 / -2; +$y = -10 / 2; +$y = (-10 / 2); +$y = (-10 / $var); +$y = 10 + -2; +$y = -10 + 2; + +$a = $x ? $y : $z; +$a = $x ? $y : $z; + +$y = 1 + 2 - 3; + +$y = 1 + 2 - 3; + +$y = 1 + 2 - 3; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true +$y = 1 + + 2 + - 3; + +$y = 1 + + 2 - + 3; + +$y = 1 ++ 2 +- 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false + +if (true || -1 == $b) { +} + +$var = array(-1); +$var = [-1]; +$var = [0, -1, -2]; + +$y = array(&$x); +$y = [&$x]; +$y = array(&$a, &$b, &$c); +$y = [&$a, &$b, &$c]; +$y = array(&$a => 1, 2 => &$b, &$c); +$y = [&$a => 1, 2 => &$b, &$c]; + +if ($a <=> $b) { +} + +if ($a <=> $b) { +} + +$a |= $b; +$a **= $b; +$a ??= $b; + +$a = +1; + +function bar($boo = +1) {} + +$username = $_GET['user'] ?? 'nobody'; + +function foo(string $bar, array $baz, ?MyClass $object) : MyClass {} + +declare(strict_types=1); + +function foo($c = ((BAR) ? 10 : 100)) {} + +$res = $a ?: $b; +$res = $a ?: $b; +$res = $a ?: $b; +$res = $a ?: $b; + +$res = $a ? : $b; +$res = $a ? : $b; +$res = $a ? : $b; +$res = $a ? : $b; + +function foo(string $a = '', ?string $b = ''): ?string {} + +// Issue #1605. +$text = preg_replace_callback( + self::CHAR_REFS_REGEX, + [ 'Sanitizer', 'decodeCharReferencesCallback' ], + $text, /* limit */ -1, $count ); + +if (true || /* test */ -1 == $b) {} +$y = 10 + /* test */ -2; + +// Issue #1604. +Hooks::run( 'ParserOptionsRegister', [ + &self::$defaults, + &self::$inCacheKey, + &self::$lazyOptions, +] ); + +$x = $foo ? function (): int { + return 1; +} : $bar; + +$x = $foo ? function ($foo) + // comment + : int { + return 1; +} : $bar; + +$x = $foo ? function ($foo) use /* comment */ ($bar): int { + return 1; +} : $bar; + +$x = !$foo ? $bar : function (): int { + return 1; +}; + +$a = + // Comment. + [ + 'a', + 'b', + ]; + +$a = +// phpcs:ignore Standard.Category.Sniff -- for reasons. +[ + 'a', + 'b', +]; + +$foo = is_array($bar) ? array_map( + function () {}, + $bar + ) : $bar; + +function bar(): array {} + +if ($line{-1} === ':') { + $line = substr($line, 0, -1); +} + +$a = $a instanceof $b; +$a = $a instanceof $b; +$a = ($a) instanceof $b; + +fn&($x) => $x; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false +$a = 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true +yield -1; +echo -1; +$a = -1; +func(-1); +$a = [-1]; +return -1; +print -1; +$a &= -1; +switch ($a) { + case -1: +} +$a = $a ?? -1; +$a .= -1; +$a /= -1; +$a = [1 => -1]; +$a = $a == -1; +$a = $a >= -1; +$a = $a === -1; +$a = $a != -1; +$a = $a !== -1; +$a = $a <= -1; +$a = $a <=> -1; +$a = $a and -1; +$a = $a or -1; +$a = $a xor -1; +$a -= -1; +$a %= -1; +$a *= -1; +$a |= -1; +$a += -1; +$a = $a ** -1; +$a **= -1; +$a = $a << -1; +$a <<= -1; +$a = $a >> -1; +$a >>= -1; +$a = (string) -1; +$a = (array) -1; +$a = (bool) -1; +$a = (object) -1; +$a = (unset) -1; +$a = (float) -1; +$a = (int) -1; +$a ^= -1; +$a = [$a, -1]; +$a = $a[-1]; +$a = $a ? -1 : -1; + +yield - 1; +echo - 1; +$a = - 1; +func(- 1); +$a = [- 1]; +return - 1; +print - 1; +$a &= - 1; +switch ($a) { + case - 1: +} +$a = $a ?? - 1; +$a .= - 1; +$a /= - 1; +$a = [1 => - 1]; +$a = $a == - 1; +$a = $a >= - 1; +$a = $a === - 1; +$a = $a != - 1; +$a = $a !== - 1; +$a = $a <= - 1; +$a = $a <=> - 1; +$a = $a and - 1; +$a = $a or - 1; +$a = $a xor - 1; +$a -= - 1; +$a %= - 1; +$a *= - 1; +$a |= - 1; +$a += - 1; +$a = $a ** - 1; +$a **= - 1; +$a = $a << - 1; +$a <<= - 1; +$a = $a >> - 1; +$a >>= - 1; +$a = (string) - 1; +$a = (array) - 1; +$a = (bool) - 1; +$a = (object) - 1; +$a = (unset) - 1; +$a = (float) - 1; +$a = (int) - 1; +$a ^= - 1; +$a = [$a, - 1]; +$a = $a[- 1]; +$a = $a ? - 1 : - 1; + + +yield -$b; +echo -$b; +$a = -$b; +func(-$b); +$a = [-$b]; +return -$b; +print -$b; +$a &= -$b; +switch ($a) { + case -$b: +} +$a = $a ?? -$b; +$a .= -$b; +$a /= -$b; +$a = [1 => -$b]; +$a = $a == -$b; +$a = $a >= -$b; +$a = $a === -$b; +$a = $a != -$b; +$a = $a !== -$b; +$a = $a <= -$b; +$a = $a <=> -$b; +$a = $a and -$b; +$a = $a or -$b; +$a = $a xor -$b; +$a -= -$b; +$a %= -$b; +$a *= -$b; +$a |= -$b; +$a += -$b; +$a = $a ** -$b; +$a **= -$b; +$a = $a << -$b; +$a <<= -$b; +$a = $a >> -$b; +$a >>= -$b; +$a = (string) -$b; +$a = (array) -$b; +$a = (bool) -$b; +$a = (object) -$b; +$a = (unset) -$b; +$a = (float) -$b; +$a = (int) -$b; +$a ^= -$b; +$a = [$a, -$b]; +$a = $a[-$b]; +$a = $a ? -$b : -$b; + +yield - $b; +echo - $b; +$a = - $b; +func(- $b); +$a = [- $b]; +return - $b; +print - $b; +$a &= - $b; +switch ($a) { + case - $b: +} +$a = $a ?? - $b; +$a .= - $b; +$a /= - $b; +$a = [1 => - $b]; +$a = $a == - $b; +$a = $a >= - $b; +$a = $a === - $b; +$a = $a != - $b; +$a = $a !== - $b; +$a = $a <= - $b; +$a = $a <=> - $b; +$a = $a and - $b; +$a = $a or - $b; +$a = $a xor - $b; +$a -= - $b; +$a %= - $b; +$a *= - $b; +$a |= - $b; +$a += - $b; +$a = $a ** - $b; +$a **= - $b; +$a = $a << - $b; +$a <<= - $b; +$a = $a >> - $b; +$a >>= - $b; +$a = (string) - $b; +$a = (array) - $b; +$a = (bool) - $b; +$a = (object) - $b; +$a = (unset) - $b; +$a = (float) - $b; +$a = (int) - $b; +$a ^= - $b; +$a = [$a, - $b]; +$a = $a[- $b]; +$a = $a ? - $b : - $b; + +exit -1; + +$cl = function ($boo =-1) {}; +$cl = function ($boo =+1) {}; +$fn = fn ($boo =-1) => $boo; +$fn = fn ($boo =+1) => $boo; + +$fn = static fn(DateTime $a, DateTime $b): int => -($a->getTimestamp() <=> $b->getTimestamp()); + +$a = 'a '.-MY_CONSTANT; +$a = 'a '.-$b; +$a = 'a '.- MY_CONSTANT; +$a = 'a '.- $b; + +match ($a) { + 'a' => -1, + 'b', 'c', 'd' => -2, + default => -3, +}; + +$foo = $var ? 10 : true; + +// Safeguard that a non-fixable error is thrown when there is a new line before the operator, +// but the last non-whitespace token before the operator is a comment token. +$foo = $var // Comment + ? false /* Comment */ + : true; + +$foo = $var // phpcs: ignore Stnd.Cat.Sniff -- for reasons. + + + ? $something /** + * Don't ask, but someone might have a docblock between the lines. It's valid PHP after all. + */ + + + : true; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true +$foo = $var // Comment + ? false // Comment + : true; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.2.inc new file mode 100644 index 000000000..3a0dbac3e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.2.inc @@ -0,0 +1,3 @@ + $j && $k< $l && $m>= $n && $o<= $p && $q<> $r; - -$a ==$b && $c !=$d && $e ===$f && $g !==$h; -$i >$j && $k <$l && $m >=$n && $o <=$p && $q <>$r; - -function myFunction($variable=0, $var2='string') {} - -if (index > -1) { -} - -array_walk_recursive($array, function(&$item) use (&$something) { -}); - -$var = saveFile(&$model, &$foo); - -// This is all valid. -$boo = -$foo; -function foo($boo = -1) {} -$foo = array('boo' => -1); -$x = $test ? -1 : 1; -$y = $test ? 1 : -1; -$z = $test ?: false; - -$closureWithDefaultParameter = function (array $testArray=array()) {}; - -switch ($foo) { - case -1: - break; -} - -$y = 1 * -1; -$y = -1 * 1; -$y = -1 * $var; -$y = 10 / -2; -$y = -10 / 2; -$y = (-10 / 2); -$y = (-10 / $var); -$y = 10 + -2; -$y = -10 + 2; - -$a = $x?$y:$z; -$a = $x ? $y : $z; - -$y = 1 - + 2 - - 3; - -$y = 1 + - 2 - - 3; - -$y = 1 -+ 2 -- 3; - -// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true -$y = 1 - + 2 - - 3; - -$y = 1 + - 2 - - 3; - -$y = 1 -+ 2 -- 3; -// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false - -if (true || -1 == $b) { -} - -$var = array(-1); -$var = [-1]; -$var = [0, -1, -2]; - -$y = array(&$x); -$y = [&$x]; -$y = array(&$a, &$b, &$c); -$y = [&$a, &$b, &$c]; -$y = array(&$a => 1, 2 => &$b, &$c); -$y = [&$a => 1, 2 => &$b, &$c]; - -if ($a <=> $b) { -} - -if ($a <=>$b) { -} - -$a |= $b; -$a **= $b; -$a ??= $b; - -$a = +1; - -function bar($boo = +1) {} - -$username = $_GET['user']??'nobody'; - -function foo(string $bar, array $baz, ?MyClass $object) : MyClass {} - -declare(strict_types=1); - -function foo($c = ((BAR)?10:100)) {} - -$res = $a ?: $b; -$res = $a ?: $b; -$res = $a ?: $b; -$res = $a ?: $b; - -$res = $a ? : $b; -$res = $a ? : $b; -$res = $a ? : $b; -$res = $a ? : $b; - -function foo(string $a = '', ?string $b = ''): ?string {} - -// Issue #1605. -$text = preg_replace_callback( - self::CHAR_REFS_REGEX, - [ 'Sanitizer', 'decodeCharReferencesCallback' ], - $text, /* limit */ -1, $count ); - -if (true || /* test */ -1 == $b) {} -$y = 10 + /* test */ -2; - -// Issue #1604. -Hooks::run( 'ParserOptionsRegister', [ - &self::$defaults, - &self::$inCacheKey, - &self::$lazyOptions, -] ); - -$x = $foo ? function (): int { - return 1; -} : $bar; - -$x = $foo ? function ($foo) - // comment - : int { - return 1; -} : $bar; - -$x = $foo ? function ($foo) use /* comment */ ($bar): int { - return 1; -} : $bar; - -$x = !$foo ? $bar : function (): int { - return 1; -}; - -$a = - // Comment. - [ - 'a', - 'b', - ]; - -$a = -// phpcs:ignore Standard.Category.Sniff -- for reasons. -[ - 'a', - 'b', -]; - -$foo = is_array($bar) ? array_map( - function () {}, - $bar - ) : $bar; - -function bar(): array {} - -if ($line{-1} === ':') { - $line = substr($line, 0, -1); -} - -$a = $a instanceof $b; -$a = $a instanceof $b; -$a = ($a)instanceof$b; - -fn&($x) => $x; - -// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false -$a = 3; - -yield -1; -echo -1; -$a = -1; -func(-1); -$a = [-1]; -return -1; -print -1; -$a &= -1; -switch ($a) { - case -1: -} -$a = $a ?? -1; -$a .= -1; -$a /= -1; -$a = [1 => -1]; -$a = $a == -1; -$a = $a >= -1; -$a = $a === -1; -$a = $a != -1; -$a = $a !== -1; -$a = $a <= -1; -$a = $a <=> -1; -$a = $a and -1; -$a = $a or -1; -$a = $a xor -1; -$a -= -1; -$a %= -1; -$a *= -1; -$a |= -1; -$a += -1; -$a = $a ** -1; -$a **= -1; -$a = $a << -1; -$a <<= -1; -$a = $a >> -1; -$a >>= -1; -$a = (string) -1; -$a = (array) -1; -$a = (bool) -1; -$a = (object) -1; -$a = (unset) -1; -$a = (float) -1; -$a = (int) -1; -$a ^= -1; -$a = [$a, -1]; -$a = $a[-1]; -$a = $a ? -1 : -1; - -yield - 1; -echo - 1; -$a = - 1; -func(- 1); -$a = [- 1]; -return - 1; -print - 1; -$a &= - 1; -switch ($a) { - case - 1: -} -$a = $a ?? - 1; -$a .= - 1; -$a /= - 1; -$a = [1 => - 1]; -$a = $a == - 1; -$a = $a >= - 1; -$a = $a === - 1; -$a = $a != - 1; -$a = $a !== - 1; -$a = $a <= - 1; -$a = $a <=> - 1; -$a = $a and - 1; -$a = $a or - 1; -$a = $a xor - 1; -$a -= - 1; -$a %= - 1; -$a *= - 1; -$a |= - 1; -$a += - 1; -$a = $a ** - 1; -$a **= - 1; -$a = $a << - 1; -$a <<= - 1; -$a = $a >> - 1; -$a >>= - 1; -$a = (string) - 1; -$a = (array) - 1; -$a = (bool) - 1; -$a = (object) - 1; -$a = (unset) - 1; -$a = (float) - 1; -$a = (int) - 1; -$a ^= - 1; -$a = [$a, - 1]; -$a = $a[- 1]; -$a = $a ? - 1 : - 1; - - -yield -$b; -echo -$b; -$a = -$b; -func(-$b); -$a = [-$b]; -return -$b; -print -$b; -$a &= -$b; -switch ($a) { - case -$b: -} -$a = $a ?? -$b; -$a .= -$b; -$a /= -$b; -$a = [1 => -$b]; -$a = $a == -$b; -$a = $a >= -$b; -$a = $a === -$b; -$a = $a != -$b; -$a = $a !== -$b; -$a = $a <= -$b; -$a = $a <=> -$b; -$a = $a and -$b; -$a = $a or -$b; -$a = $a xor -$b; -$a -= -$b; -$a %= -$b; -$a *= -$b; -$a |= -$b; -$a += -$b; -$a = $a ** -$b; -$a **= -$b; -$a = $a << -$b; -$a <<= -$b; -$a = $a >> -$b; -$a >>= -$b; -$a = (string) -$b; -$a = (array) -$b; -$a = (bool) -$b; -$a = (object) -$b; -$a = (unset) -$b; -$a = (float) -$b; -$a = (int) -$b; -$a ^= -$b; -$a = [$a, -$b]; -$a = $a[-$b]; -$a = $a ? -$b : -$b; - -yield - $b; -echo - $b; -$a = - $b; -func(- $b); -$a = [- $b]; -return - $b; -print - $b; -$a &= - $b; -switch ($a) { - case - $b: -} -$a = $a ?? - $b; -$a .= - $b; -$a /= - $b; -$a = [1 => - $b]; -$a = $a == - $b; -$a = $a >= - $b; -$a = $a === - $b; -$a = $a != - $b; -$a = $a !== - $b; -$a = $a <= - $b; -$a = $a <=> - $b; -$a = $a and - $b; -$a = $a or - $b; -$a = $a xor - $b; -$a -= - $b; -$a %= - $b; -$a *= - $b; -$a |= - $b; -$a += - $b; -$a = $a ** - $b; -$a **= - $b; -$a = $a << - $b; -$a <<= - $b; -$a = $a >> - $b; -$a >>= - $b; -$a = (string) - $b; -$a = (array) - $b; -$a = (bool) - $b; -$a = (object) - $b; -$a = (unset) - $b; -$a = (float) - $b; -$a = (int) - $b; -$a ^= - $b; -$a = [$a, - $b]; -$a = $a[- $b]; -$a = $a ? - $b : - $b; - -exit -1; - -$cl = function ($boo =-1) {}; -$cl = function ($boo =+1) {}; -$fn = fn ($boo =-1) => $boo; -$fn = fn ($boo =+1) => $boo; - -$fn = static fn(DateTime $a, DateTime $b): int => -($a->getTimestamp() <=> $b->getTimestamp()); - -$a = 'a '.-MY_CONSTANT; -$a = 'a '.-$b; -$a = 'a '.- MY_CONSTANT; -$a = 'a '.- $b; - -match ($a) { - 'a' => -1, - 'b', 'c', 'd' => -2, - default => -3, -}; - -/* Intentional parse error. This has to be the last test in the file. */ -$a = 10 + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed deleted file mode 100644 index 8b92a4875..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed +++ /dev/null @@ -1,481 +0,0 @@ - $j && $k < $l && $m >= $n && $o <= $p && $q <> $r; - -$a == $b && $c != $d && $e === $f && $g !== $h; -$i > $j && $k < $l && $m >= $n && $o <= $p && $q <> $r; - -function myFunction($variable=0, $var2='string') {} - -if (index > -1) { -} - -array_walk_recursive($array, function(&$item) use (&$something) { -}); - -$var = saveFile(&$model, &$foo); - -// This is all valid. -$boo = -$foo; -function foo($boo = -1) {} -$foo = array('boo' => -1); -$x = $test ? -1 : 1; -$y = $test ? 1 : -1; -$z = $test ?: false; - -$closureWithDefaultParameter = function (array $testArray=array()) {}; - -switch ($foo) { - case -1: - break; -} - -$y = 1 * -1; -$y = -1 * 1; -$y = -1 * $var; -$y = 10 / -2; -$y = -10 / 2; -$y = (-10 / 2); -$y = (-10 / $var); -$y = 10 + -2; -$y = -10 + 2; - -$a = $x ? $y : $z; -$a = $x ? $y : $z; - -$y = 1 + 2 - 3; - -$y = 1 + 2 - 3; - -$y = 1 + 2 - 3; - -// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true -$y = 1 - + 2 - - 3; - -$y = 1 + - 2 - - 3; - -$y = 1 -+ 2 -- 3; -// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false - -if (true || -1 == $b) { -} - -$var = array(-1); -$var = [-1]; -$var = [0, -1, -2]; - -$y = array(&$x); -$y = [&$x]; -$y = array(&$a, &$b, &$c); -$y = [&$a, &$b, &$c]; -$y = array(&$a => 1, 2 => &$b, &$c); -$y = [&$a => 1, 2 => &$b, &$c]; - -if ($a <=> $b) { -} - -if ($a <=> $b) { -} - -$a |= $b; -$a **= $b; -$a ??= $b; - -$a = +1; - -function bar($boo = +1) {} - -$username = $_GET['user'] ?? 'nobody'; - -function foo(string $bar, array $baz, ?MyClass $object) : MyClass {} - -declare(strict_types=1); - -function foo($c = ((BAR) ? 10 : 100)) {} - -$res = $a ?: $b; -$res = $a ?: $b; -$res = $a ?: $b; -$res = $a ?: $b; - -$res = $a ? : $b; -$res = $a ? : $b; -$res = $a ? : $b; -$res = $a ? : $b; - -function foo(string $a = '', ?string $b = ''): ?string {} - -// Issue #1605. -$text = preg_replace_callback( - self::CHAR_REFS_REGEX, - [ 'Sanitizer', 'decodeCharReferencesCallback' ], - $text, /* limit */ -1, $count ); - -if (true || /* test */ -1 == $b) {} -$y = 10 + /* test */ -2; - -// Issue #1604. -Hooks::run( 'ParserOptionsRegister', [ - &self::$defaults, - &self::$inCacheKey, - &self::$lazyOptions, -] ); - -$x = $foo ? function (): int { - return 1; -} : $bar; - -$x = $foo ? function ($foo) - // comment - : int { - return 1; -} : $bar; - -$x = $foo ? function ($foo) use /* comment */ ($bar): int { - return 1; -} : $bar; - -$x = !$foo ? $bar : function (): int { - return 1; -}; - -$a = - // Comment. - [ - 'a', - 'b', - ]; - -$a = -// phpcs:ignore Standard.Category.Sniff -- for reasons. -[ - 'a', - 'b', -]; - -$foo = is_array($bar) ? array_map( - function () {}, - $bar - ) : $bar; - -function bar(): array {} - -if ($line{-1} === ':') { - $line = substr($line, 0, -1); -} - -$a = $a instanceof $b; -$a = $a instanceof $b; -$a = ($a) instanceof $b; - -fn&($x) => $x; - -// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false -$a = 3; - -yield -1; -echo -1; -$a = -1; -func(-1); -$a = [-1]; -return -1; -print -1; -$a &= -1; -switch ($a) { - case -1: -} -$a = $a ?? -1; -$a .= -1; -$a /= -1; -$a = [1 => -1]; -$a = $a == -1; -$a = $a >= -1; -$a = $a === -1; -$a = $a != -1; -$a = $a !== -1; -$a = $a <= -1; -$a = $a <=> -1; -$a = $a and -1; -$a = $a or -1; -$a = $a xor -1; -$a -= -1; -$a %= -1; -$a *= -1; -$a |= -1; -$a += -1; -$a = $a ** -1; -$a **= -1; -$a = $a << -1; -$a <<= -1; -$a = $a >> -1; -$a >>= -1; -$a = (string) -1; -$a = (array) -1; -$a = (bool) -1; -$a = (object) -1; -$a = (unset) -1; -$a = (float) -1; -$a = (int) -1; -$a ^= -1; -$a = [$a, -1]; -$a = $a[-1]; -$a = $a ? -1 : -1; - -yield - 1; -echo - 1; -$a = - 1; -func(- 1); -$a = [- 1]; -return - 1; -print - 1; -$a &= - 1; -switch ($a) { - case - 1: -} -$a = $a ?? - 1; -$a .= - 1; -$a /= - 1; -$a = [1 => - 1]; -$a = $a == - 1; -$a = $a >= - 1; -$a = $a === - 1; -$a = $a != - 1; -$a = $a !== - 1; -$a = $a <= - 1; -$a = $a <=> - 1; -$a = $a and - 1; -$a = $a or - 1; -$a = $a xor - 1; -$a -= - 1; -$a %= - 1; -$a *= - 1; -$a |= - 1; -$a += - 1; -$a = $a ** - 1; -$a **= - 1; -$a = $a << - 1; -$a <<= - 1; -$a = $a >> - 1; -$a >>= - 1; -$a = (string) - 1; -$a = (array) - 1; -$a = (bool) - 1; -$a = (object) - 1; -$a = (unset) - 1; -$a = (float) - 1; -$a = (int) - 1; -$a ^= - 1; -$a = [$a, - 1]; -$a = $a[- 1]; -$a = $a ? - 1 : - 1; - - -yield -$b; -echo -$b; -$a = -$b; -func(-$b); -$a = [-$b]; -return -$b; -print -$b; -$a &= -$b; -switch ($a) { - case -$b: -} -$a = $a ?? -$b; -$a .= -$b; -$a /= -$b; -$a = [1 => -$b]; -$a = $a == -$b; -$a = $a >= -$b; -$a = $a === -$b; -$a = $a != -$b; -$a = $a !== -$b; -$a = $a <= -$b; -$a = $a <=> -$b; -$a = $a and -$b; -$a = $a or -$b; -$a = $a xor -$b; -$a -= -$b; -$a %= -$b; -$a *= -$b; -$a |= -$b; -$a += -$b; -$a = $a ** -$b; -$a **= -$b; -$a = $a << -$b; -$a <<= -$b; -$a = $a >> -$b; -$a >>= -$b; -$a = (string) -$b; -$a = (array) -$b; -$a = (bool) -$b; -$a = (object) -$b; -$a = (unset) -$b; -$a = (float) -$b; -$a = (int) -$b; -$a ^= -$b; -$a = [$a, -$b]; -$a = $a[-$b]; -$a = $a ? -$b : -$b; - -yield - $b; -echo - $b; -$a = - $b; -func(- $b); -$a = [- $b]; -return - $b; -print - $b; -$a &= - $b; -switch ($a) { - case - $b: -} -$a = $a ?? - $b; -$a .= - $b; -$a /= - $b; -$a = [1 => - $b]; -$a = $a == - $b; -$a = $a >= - $b; -$a = $a === - $b; -$a = $a != - $b; -$a = $a !== - $b; -$a = $a <= - $b; -$a = $a <=> - $b; -$a = $a and - $b; -$a = $a or - $b; -$a = $a xor - $b; -$a -= - $b; -$a %= - $b; -$a *= - $b; -$a |= - $b; -$a += - $b; -$a = $a ** - $b; -$a **= - $b; -$a = $a << - $b; -$a <<= - $b; -$a = $a >> - $b; -$a >>= - $b; -$a = (string) - $b; -$a = (array) - $b; -$a = (bool) - $b; -$a = (object) - $b; -$a = (unset) - $b; -$a = (float) - $b; -$a = (int) - $b; -$a ^= - $b; -$a = [$a, - $b]; -$a = $a[- $b]; -$a = $a ? - $b : - $b; - -exit -1; - -$cl = function ($boo =-1) {}; -$cl = function ($boo =+1) {}; -$fn = fn ($boo =-1) => $boo; -$fn = fn ($boo =+1) => $boo; - -$fn = static fn(DateTime $a, DateTime $b): int => -($a->getTimestamp() <=> $b->getTimestamp()); - -$a = 'a '.-MY_CONSTANT; -$a = 'a '.-$b; -$a = 'a '.- MY_CONSTANT; -$a = 'a '.- $b; - -match ($a) { - 'a' => -1, - 'b', 'c', 'd' => -2, - default => -3, -}; - -/* Intentional parse error. This has to be the last test in the file. */ -$a = 10 + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js index 16eb130f5..f37df9d86 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js @@ -101,3 +101,4 @@ var foo = bar.map(baz=> baz.length); // phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false a = 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed index 877db4678..47c89302b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed @@ -95,3 +95,4 @@ var foo = bar.map(baz => baz.length); // phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false a = 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php index 8e8ad98d0..e34a2ec4a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class OperatorSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the OperatorSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\OperatorSpacingSniff + */ +final class OperatorSpacingUnitTest extends AbstractSniffUnitTest { @@ -25,10 +30,10 @@ class OperatorSpacingUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='OperatorSpacingUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { - case 'OperatorSpacingUnitTest.inc': + case 'OperatorSpacingUnitTest.1.inc': return [ 4 => 1, 5 => 2, @@ -99,8 +104,14 @@ public function getErrorList($testFile='OperatorSpacingUnitTest.inc') 265 => 2, 266 => 2, 271 => 2, + 487 => 1, + 488 => 1, + 493 => 1, + 494 => 1, + 499 => 1, + 504 => 1, ]; - break; + case 'OperatorSpacingUnitTest.js': return [ 4 => 1, @@ -143,10 +154,9 @@ public function getErrorList($testFile='OperatorSpacingUnitTest.inc') 100 => 1, 103 => 2, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php index e80f93670..5c20b0010 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class PropertyLabelSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the PropertyLabel sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\PropertyLabelSpacingSniff + */ +final class PropertyLabelSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php index d659d6473..0729624c9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ScopeClosingBraceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ScopeClosingBrace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeClosingBraceSniff + */ +final class ScopeClosingBraceUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc new file mode 100644 index 000000000..de53edcaf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc @@ -0,0 +1,194 @@ + 'a', 'b' => 'b' ), + $varQ = 'string', + $varR = 123; + + public + $varS, + $varT, + $varU; + + // Issue #3188 - static as return type. + public static function staticAsReturnType($attributes = []): static + { + return static::factory()->create($attributes); + } + + public static function nullableStaticReturnType($attributes = []): ?static + { + return static::factory()->create($attributes); + } + + // Also account for static used within union types. + public function staticLast($attributes = []): object|static {} + public function staticMiddle(): string|static|object {} + public function staticFirst(): static|object {} +} + +// Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. +$callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; + +class TypedProperties { + public + int $var; + + protected string $stringA, $stringB; + + private bool + $boolA, + $boolB; +} + +// PHP 8.0 constructor property promotion. +class ConstructorPropertyPromotionTest { + public function __construct( + public $x = 0.0, + protected $y = '', + private $z = null, + $normalParam, + ) {} +} + +class ConstructorPropertyPromotionWithTypesTest { + public function __construct(protected float|int $x, public?string &$y = 'test', private mixed $z) {} +} + +// PHP 8.1 readonly keywords. +class ReadonlyTest { + public readonly int $publicReadonlyProperty; + + protected readonly int $protectedReadonlyProperty; + + readonly protected int $protectedReadonlyProperty; + + readonly private int $privateReadonlyProperty; + + public function __construct(readonly protected float|int $x, public readonly?string &$y = 'test') {} +} + +// PHP 8.2 readonly classes. +readonly class ReadonlyClassTest {} +readonly class ReadonlyClassTest {} + +// PHP 8.3 readonly anonymous classes. +$anon = new readonly class {}; +$anon = new readonly class {}; + +class FinalTest { + final public static function create(ContainerInterface $container) {} +} + +final class FinalTest2 { +} + +final + readonly class FinalTest3 {} + +class FinalTest4 { + final const X = "foo"; + final public const Y = "bar"; +} + +abstract class AbstractTest { + abstract public function foo(); +} + +final class FinalSpacingCorrect { + public final const SPACING_CORRECT = true; +} + +abstract class AbstractSpacingCorrect { + public abstract function spacingCorrect() {} +} + +$closure = static function() { return 'spacing correct'; }; +$closure = static function() { return 'spacing incorrect'; }; + +class ConstantVisibility { + public const PUBLIC_SPACING_CORRECT = true; + protected const PROTECTED_SPACING_CORRECT = true; + private const PRIVATE_SPACING_CORRECT = true; + + public const PUBLIC_SPACING_INCORRECT = true; + protected const PROTECTED_SPACING_INCORRECT = true; + private const PRIVATE_SPACING_INCORRECT = true; +} + +class FinalProperties { + final readonly public ?MyType $spacing_correct; + protected final $spacing_incorrect = 'foo'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed new file mode 100644 index 000000000..55d1a5492 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed @@ -0,0 +1,187 @@ + 'a', 'b' => 'b' ), + $varQ = 'string', + $varR = 123; + + public + $varS, + $varT, + $varU; + + // Issue #3188 - static as return type. + public static function staticAsReturnType($attributes = []): static + { + return static::factory()->create($attributes); + } + + public static function nullableStaticReturnType($attributes = []): ?static + { + return static::factory()->create($attributes); + } + + // Also account for static used within union types. + public function staticLast($attributes = []): object|static {} + public function staticMiddle(): string|static|object {} + public function staticFirst(): static|object {} +} + +// Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. +$callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; + +class TypedProperties { + public int $var; + + protected string $stringA, $stringB; + + private bool + $boolA, + $boolB; +} + +// PHP 8.0 constructor property promotion. +class ConstructorPropertyPromotionTest { + public function __construct( + public $x = 0.0, + protected $y = '', + private $z = null, + $normalParam, + ) {} +} + +class ConstructorPropertyPromotionWithTypesTest { + public function __construct(protected float|int $x, public ?string &$y = 'test', private mixed $z) {} +} + +// PHP 8.1 readonly keywords. +class ReadonlyTest { + public readonly int $publicReadonlyProperty; + + protected readonly int $protectedReadonlyProperty; + + readonly protected int $protectedReadonlyProperty; + + readonly private int $privateReadonlyProperty; + + public function __construct(readonly protected float|int $x, public readonly ?string &$y = 'test') {} +} + +// PHP 8.2 readonly classes. +readonly class ReadonlyClassTest {} +readonly class ReadonlyClassTest {} + +// PHP 8.3 readonly anonymous classes. +$anon = new readonly class {}; +$anon = new readonly class {}; + +class FinalTest { + final public static function create(ContainerInterface $container) {} +} + +final class FinalTest2 { +} + +final readonly class FinalTest3 {} + +class FinalTest4 { + final const X = "foo"; + final public const Y = "bar"; +} + +abstract class AbstractTest { + abstract public function foo(); +} + +final class FinalSpacingCorrect { + public final const SPACING_CORRECT = true; +} + +abstract class AbstractSpacingCorrect { + public abstract function spacingCorrect() {} +} + +$closure = static function() { return 'spacing correct'; }; +$closure = static function() { return 'spacing incorrect'; }; + +class ConstantVisibility { + public const PUBLIC_SPACING_CORRECT = true; + protected const PROTECTED_SPACING_CORRECT = true; + private const PRIVATE_SPACING_CORRECT = true; + + public const PUBLIC_SPACING_INCORRECT = true; + protected const PROTECTED_SPACING_INCORRECT = true; + private const PRIVATE_SPACING_INCORRECT = true; +} + +class FinalProperties { + final readonly public ?MyType $spacing_correct; + protected final $spacing_incorrect = 'foo'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.2.inc new file mode 100644 index 000000000..45cfb5343 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.2.inc @@ -0,0 +1,6 @@ + 'a', 'b' => 'b' ), - $varQ = 'string', - $varR = 123; - - // Intentionally missing a semi-colon for testing. - public - $varS, - $varT -} - -// Issue #3188 - static as return type. -public static function fCreate($attributes = []): static -{ - return static::factory()->create($attributes); -} - -public static function fCreate($attributes = []): ?static -{ - return static::factory()->create($attributes); -} - -// Also account for static used within union types. -public function fCreate($attributes = []): object|static -{ -} - -// Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. -$callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; - -class TypedProperties { - public - int $var; - - protected string $stringA, $stringB; - - private bool - $boolA, - $boolB; -} - -// PHP 8.0 constructor property promotion. -class ConstructorPropertyPromotionTest { - public function __construct( - public $x = 0.0, - protected $y = '', - private $z = null, - $normalParam, - ) {} -} - -class ConstructorPropertyPromotionWithTypesTest { - public function __construct(protected float|int $x, public?string &$y = 'test', private mixed $z) {} -} - -// PHP 8.1 readonly keywords. -class ReadonlyTest { - public readonly int $publicReadonlyProperty; - - protected readonly int $protectedReadonlyProperty; - - readonly protected int $protectedReadonlyProperty; - - readonly private int $privateReadonlyProperty; - - public function __construct(readonly protected float|int $x, public readonly?string &$y = 'test') {} -} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc.fixed deleted file mode 100644 index d3b682ed7..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc.fixed +++ /dev/null @@ -1,135 +0,0 @@ - 'a', 'b' => 'b' ), - $varQ = 'string', - $varR = 123; - - // Intentionally missing a semi-colon for testing. - public - $varS, - $varT -} - -// Issue #3188 - static as return type. -public static function fCreate($attributes = []): static -{ - return static::factory()->create($attributes); -} - -public static function fCreate($attributes = []): ?static -{ - return static::factory()->create($attributes); -} - -// Also account for static used within union types. -public function fCreate($attributes = []): object|static -{ -} - -// Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. -$callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; - -class TypedProperties { - public int $var; - - protected string $stringA, $stringB; - - private bool - $boolA, - $boolB; -} - -// PHP 8.0 constructor property promotion. -class ConstructorPropertyPromotionTest { - public function __construct( - public $x = 0.0, - protected $y = '', - private $z = null, - $normalParam, - ) {} -} - -class ConstructorPropertyPromotionWithTypesTest { - public function __construct(protected float|int $x, public ?string &$y = 'test', private mixed $z) {} -} - -// PHP 8.1 readonly keywords. -class ReadonlyTest { - public readonly int $publicReadonlyProperty; - - protected readonly int $protectedReadonlyProperty; - - readonly protected int $protectedReadonlyProperty; - - readonly private int $privateReadonlyProperty; - - public function __construct(readonly protected float|int $x, public readonly ?string &$y = 'test') {} -} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.php index 30b66215c..64b82e365 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ScopeKeywordSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ScopeKeywordSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeKeywordSpacingSniff + */ +final class ScopeKeywordSpacingUnitTest extends AbstractSniffUnitTest { @@ -21,33 +26,58 @@ class ScopeKeywordSpacingUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 7 => 2, - 8 => 1, - 13 => 1, - 14 => 1, - 15 => 1, - 17 => 2, - 26 => 1, - 28 => 1, - 29 => 1, - 64 => 1, - 67 => 1, - 71 => 1, - 103 => 1, - 106 => 1, - 111 => 1, - 119 => 1, - 121 => 1, - 127 => 2, - 134 => 2, - 138 => 2, - 140 => 3, - ]; + switch ($testFile) { + case 'ScopeKeywordSpacingUnitTest.1.inc': + return [ + 7 => 2, + 8 => 1, + 13 => 1, + 14 => 1, + 15 => 1, + 17 => 2, + 26 => 1, + 28 => 1, + 29 => 1, + 64 => 1, + 67 => 1, + 71 => 1, + 103 => 1, + 106 => 1, + 111 => 1, + 119 => 1, + 121 => 1, + 127 => 2, + 134 => 2, + 138 => 2, + 140 => 3, + 145 => 1, + 149 => 1, + 152 => 1, + 155 => 1, + 158 => 1, + 162 => 1, + 163 => 1, + 166 => 1, + 167 => 1, + 179 => 1, + 186 => 1, + 187 => 1, + 188 => 1, + 193 => 2, + ]; + + case 'ScopeKeywordSpacingUnitTest.3.inc': + return [6 => 1]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc index 393f48454..60f87e5bc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc @@ -18,14 +18,14 @@ $sum = $a /* + $b + $c */ ; /* - * Test that the sniff does *not* throw incorrect errors for semi-colons in + * Test that the sniff does *not* throw incorrect errors for semicolons in * "empty" parts of a `for` control structure. */ for ($i = 1; ; $i++) {} for ( ; $ptr >= 0; $ptr-- ) {} for ( ; ; ) {} -// But it should when the semi-colon in a `for` follows a comment (but shouldn't move the semi-colon). +// But it should when the semicolon in a `for` follows a comment (but shouldn't move the semicolon). for ( /* Deliberately left empty. */ ; $ptr >= 0; $ptr-- ) {} for ( $i = 1 ; /* Deliberately left empty. */ ; $i++ ) {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed index 0d06324de..b4dc0f13e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed @@ -18,14 +18,14 @@ $sum = $a; /* + $b + $c */ /* - * Test that the sniff does *not* throw incorrect errors for semi-colons in + * Test that the sniff does *not* throw incorrect errors for semicolons in * "empty" parts of a `for` control structure. */ for ($i = 1; ; $i++) {} for ( ; $ptr >= 0; $ptr-- ) {} for ( ; ; ) {} -// But it should when the semi-colon in a `for` follows a comment (but shouldn't move the semi-colon). +// But it should when the semicolon in a `for` follows a comment (but shouldn't move the semicolon). for ( /* Deliberately left empty. */; $ptr >= 0; $ptr-- ) {} for ( $i = 1; /* Deliberately left empty. */; $i++ ) {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php index 72196f8e7..218666dc0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class SemicolonSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the SemicolonSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SemicolonSpacingSniff + */ +final class SemicolonSpacingUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class SemicolonSpacingUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='SemicolonSpacingUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'SemicolonSpacingUnitTest.inc': @@ -43,7 +48,7 @@ public function getErrorList($testFile='SemicolonSpacingUnitTest.inc') 30 => 2, 36 => 1, ]; - break; + case 'SemicolonSpacingUnitTest.js': return [ 3 => 1, @@ -56,10 +61,9 @@ public function getErrorList($testFile='SemicolonSpacingUnitTest.inc') 22 => 1, 25 => 1, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css index 1dd1b6e6b..e3f3f0291 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css @@ -23,3 +23,10 @@ } /* phpcs:set Squiz.WhiteSpace.SuperfluousWhitespace ignoreBlankLines false */ +// /** +// * This text is in two types of comment: each line is commented out +// * individually, and the whole block is in what looks like a +// * docblock-comment. This sniff should ignore all this text as there +// * is no superfluous white-space here. +// */ + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed index 59ddddb08..11be21d5c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed @@ -21,3 +21,10 @@ float: left; } /* phpcs:set Squiz.WhiteSpace.SuperfluousWhitespace ignoreBlankLines false */ + +// /** +// * This text is in two types of comment: each line is commented out +// * individually, and the whole block is in what looks like a +// * docblock-comment. This sniff should ignore all this text as there +// * is no superfluous white-space here. +// */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php index b9ff96fbc..4f7c7cdbc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class SuperfluousWhitespaceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the SuperfluousWhitespace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SuperfluousWhitespaceSniff + */ +final class SuperfluousWhitespaceUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class SuperfluousWhitespaceUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='SuperfluousWhitespaceUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'SuperfluousWhitespaceUnitTest.1.inc': @@ -44,26 +49,26 @@ public function getErrorList($testFile='SuperfluousWhitespaceUnitTest.inc') 65 => 1, 73 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.2.inc': return [ 2 => 1, 8 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.3.inc': return [ 6 => 1, 10 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.4.inc': case 'SuperfluousWhitespaceUnitTest.5.inc': return [ 1 => 1, 4 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.1.js': return [ 1 => 1, @@ -77,19 +82,18 @@ public function getErrorList($testFile='SuperfluousWhitespaceUnitTest.inc') 38 => 1, 56 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.1.css': return [ 1 => 1, 8 => 1, 9 => 1, 11 => 1, - 25 => 1, + 32 => 1, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml index 87ab4c3e8..82f5270ad 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml @@ -74,8 +74,14 @@ - - + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml index aa60b8ab9..f1dca3c67 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml @@ -1,7 +1,7 @@ @@ -11,7 +11,7 @@ $var = 1; ]]> - + * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * + * @deprecated 3.9.0 */ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\Debug; @@ -23,7 +25,7 @@ class CodeAnalyzerSniff implements Sniff /** * Returns the token types that this sniff is interested in. * - * @return int[] + * @return array */ public function register() { @@ -46,7 +48,7 @@ public function process(File $phpcsFile, $stackPtr) { $analyzerPath = Config::getExecutablePath('zend_ca'); if ($analyzerPath === null) { - return; + return $phpcsFile->numTokens; } $fileName = $phpcsFile->getFilename(); @@ -67,7 +69,7 @@ public function process(File $phpcsFile, $stackPtr) // provide useful error reporting. if (is_numeric($exitCode) === true && $exitCode > 0) { if (is_array($output) === true) { - $msg = join('\n', $output); + $msg = implode('\n', $output); } throw new RuntimeException("Failed invoking ZendCodeAnalyzer, exitcode was [$exitCode], retval was [$retval], output was [$msg]"); @@ -90,7 +92,7 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php index 0ed34d13c..7b547bfd8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php @@ -4,13 +4,13 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\Files; -use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; class ClosingTagSniff implements Sniff @@ -20,7 +20,7 @@ class ClosingTagSniff implements Sniff /** * Returns an array of tokens this test wants to listen for. * - * @return array + * @return array */ public function register() { @@ -36,7 +36,7 @@ public function register() * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * - * @return void + * @return int */ public function process(File $phpcsFile, $stackPtr) { @@ -71,7 +71,7 @@ public function process(File $phpcsFile, $stackPtr) }//end if // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php index 267cd0ad6..41b194810 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -4,14 +4,14 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions; +use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractVariableSniff; use PHP_CodeSniffer\Util\Common; -use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; class ValidVariableNameSniff extends AbstractVariableSniff diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php index efd3b900e..82781a7d6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Tests\Debug; @@ -12,14 +12,19 @@ use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; use PHP_CodeSniffer\Config; -class CodeAnalyzerUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the CodeAnalyzer sniff. + * + * @covers \PHP_CodeSniffer\Standards\Zend\Sniffs\Debug\CodeAnalyzerSniff + */ +final class CodeAnalyzerUnitTest extends AbstractSniffUnitTest { /** * Should this test be skipped for some reason. * - * @return void + * @return bool */ protected function shouldSkipTest() { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php index 4a42cde09..0a031486b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Tests\Files; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ClosingTagUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ClosingTag sniff. + * + * @covers \PHP_CodeSniffer\Standards\Zend\Sniffs\Files\ClosingTagSniff + */ +final class ClosingTagUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php index e57c73564..c66a2a42c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Tests\NamingConventions; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ValidVariableNameUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ValidVariableName sniff. + * + * @covers \PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff + */ +final class ValidVariableNameUnitTest extends AbstractSniffUnitTest { @@ -87,6 +92,7 @@ public function getWarningList() 79 => 1, 82 => 1, 94 => 1, + // Warning from getMemberProperties() about parse error. 107 => 1, ]; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php index b7c2018bc..36631ddc3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; @@ -22,7 +22,7 @@ class CSS extends PHP * * Pre-checks the content to see if it looks minified. * - * @param string $content The content to tokenize, + * @param string $content The content to tokenize. * @param \PHP_CodeSniffer\Config $config The config data for the run. * @param string $eolChar The EOL char used in the content. * @@ -196,7 +196,11 @@ public function tokenize($string) // The first and last tokens are the open/close tags. array_shift($commentTokens); - array_pop($commentTokens); + $closeTag = array_pop($commentTokens); + + while ($closeTag['content'] !== '?'.'>') { + $closeTag = array_pop($commentTokens); + } if ($leadingZero === true) { $commentTokens[0]['content'] = substr($commentTokens[0]['content'], 1); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php index beba53c2b..e779c84a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php @@ -4,28 +4,25 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; class Comment { /** - * Creates an array of tokens when given some PHP code. + * Splits a single doc block comment token up into something that can be easily iterated over. * - * Starts by using token_get_all() but does a lot of extra processing - * to insert information about the context of the token. - * - * @param string $string The string to tokenize. + * @param string $string The doc block comment string to parse. * @param string $eolChar The EOL character to use for splitting strings. - * @param int $stackPtr The position of the first token in the file. + * @param int $stackPtr The position of the token in the "new"/final token stream. * - * @return array + * @return array>> */ public function tokenizeString($string, $eolChar, $stackPtr) { @@ -41,9 +38,16 @@ public function tokenizeString($string, $eolChar, $stackPtr) extra star when they are used for function and class comments. */ - $char = ($numChars - strlen(ltrim($string, '/*'))); - $openTag = substr($string, 0, $char); - $string = ltrim($string, '/*'); + $char = ($numChars - strlen(ltrim($string, '/*'))); + $lastChars = substr($string, -2); + if ($char === $numChars && $lastChars === '*/') { + // Edge case: docblock without whitespace or contents. + $openTag = substr($string, 0, -2); + $string = $lastChars; + } else { + $openTag = substr($string, 0, $char); + $string = ltrim($string, '/*'); + } $tokens[$stackPtr] = [ 'content' => $openTag, @@ -56,7 +60,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) $stackPtr++; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($openTag); + $content = Common::prepareForOutput($openTag); echo "\t\tCreate comment token: T_DOC_COMMENT_OPEN_TAG => $content".PHP_EOL; } @@ -74,6 +78,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) ]; if ($closeTag['content'] === false) { + // In PHP < 8.0 substr() can return `false` instead of always returning a string. $closeTag['content'] = ''; } @@ -99,7 +104,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) $tokens[$stackPtr] = $space; $stackPtr++; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($space['content']); + $content = Common::prepareForOutput($space['content']); echo "\t\tCreate comment token: T_DOC_COMMENT_WHITESPACE => $content".PHP_EOL; } @@ -134,7 +139,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) foreach ($lineTokens as $lineToken) { $tokens[$stackPtr] = $lineToken; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($lineToken['content']); + $content = Common::prepareForOutput($lineToken['content']); $type = $lineToken['type']; echo "\t\tCreate comment token: $type => $content".PHP_EOL; } @@ -150,7 +155,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) $tokens[$stackPtr] = $closeTag; $tokens[$openPtr]['comment_closer'] = $stackPtr; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($closeTag['content']); + $content = Common::prepareForOutput($closeTag['content']); echo "\t\tCreate comment token: T_DOC_COMMENT_CLOSE_TAG => $content".PHP_EOL; } @@ -171,7 +176,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) * @param int $start The position in the string to start processing. * @param int $end The position in the string to end processing. * - * @return array + * @return array> */ private function processLine($string, $eolChar, $start, $end) { @@ -246,7 +251,7 @@ private function processLine($string, $eolChar, $start, $end) * @param int $start The position in the string to start processing. * @param int $end The position in the string to end processing. * - * @return array|null + * @return array|null */ private function collectWhitespace($string, $start, $end) { @@ -263,14 +268,12 @@ private function collectWhitespace($string, $start, $end) return null; } - $token = [ + return [ 'content' => $space, 'code' => T_DOC_COMMENT_WHITESPACE, 'type' => 'T_DOC_COMMENT_WHITESPACE', ]; - return $token; - }//end collectWhitespace() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php index ee2f84294..c7249fcd9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; @@ -251,7 +251,7 @@ class JS extends Tokenizer * * Pre-checks the content to see if it looks minified. * - * @param string $content The content to tokenize, + * @param string $content The content to tokenize. * @param \PHP_CodeSniffer\Config $config The config data for the run. * @param string $eolChar The EOL char used in the content. * @@ -905,10 +905,10 @@ public function tokenize($string) * * If a regular expression is not found, NULL is returned. * - * @param string $char The index of the possible regex start character. + * @param int $char The index of the possible regex start character. * @param string $string The complete content of the string being tokenized. - * @param string $chars An array of characters being tokenized. - * @param string $tokens The current array of tokens found in the string. + * @param array $chars An array of characters being tokenized. + * @param array $tokens The current array of tokens found in the string. * * @return array|null */ @@ -1188,7 +1188,7 @@ public function processAdditional() } } } else if ($this->tokens[$i]['code'] === T_CLOSE_OBJECT) { - $opener = array_pop($classStack); + array_pop($classStack); } else if ($this->tokens[$i]['code'] === T_COLON) { // If it is a scope opener, it belongs to a // DEFAULT or CASE statement. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php index 3fc67b0c8..73a0c4b4a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php @@ -4,12 +4,13 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\Tokens; class PHP extends Tokenizer { @@ -230,6 +231,7 @@ class PHP extends Tokenizer T_CONTINUE => T_CONTINUE, T_THROW => T_THROW, T_EXIT => T_EXIT, + T_GOTO => T_GOTO, ], 'strict' => true, 'shared' => true, @@ -250,6 +252,7 @@ class PHP extends Tokenizer T_CONTINUE => T_CONTINUE, T_THROW => T_THROW, T_EXIT => T_EXIT, + T_GOTO => T_GOTO, ], 'strict' => true, 'shared' => true, @@ -306,7 +309,7 @@ class PHP extends Tokenizer /** * Known lengths of tokens. * - * @var array + * @var array */ public $knownLengths = [ T_ABSTRACT => 8, @@ -463,6 +466,8 @@ class PHP extends Tokenizer T_CLOSE_SHORT_ARRAY => 1, T_TYPE_UNION => 1, T_TYPE_INTERSECTION => 1, + T_TYPE_OPEN_PARENTHESIS => 1, + T_TYPE_CLOSE_PARENTHESIS => 1, ]; /** @@ -526,8 +531,9 @@ protected function tokenize($string) $numTokens = count($tokens); $lastNotEmptyToken = 0; - $insideInlineIf = []; - $insideUseGroup = false; + $insideInlineIf = []; + $insideUseGroup = false; + $insideConstDeclaration = false; $commentTokenizer = new Comment(); @@ -542,12 +548,12 @@ protected function tokenize($string) if (PHP_CODESNIFFER_VERBOSITY > 1) { if ($tokenIsArray === true) { - $type = Util\Tokens::tokenName($token[0]); - $content = Util\Common::prepareForOutput($token[1]); + $type = Tokens::tokenName($token[0]); + $content = Common::prepareForOutput($token[1]); } else { $newToken = self::resolveSimpleToken($token[0]); $type = $newToken['type']; - $content = Util\Common::prepareForOutput($token[0]); + $content = Common::prepareForOutput($token[0]); } echo "\tProcess token "; @@ -561,7 +567,7 @@ protected function tokenize($string) }//end if if ($newStackPtr > 0 - && isset(Util\Tokens::$emptyTokens[$finalTokens[($newStackPtr - 1)]['code']]) === false + && isset(Tokens::$emptyTokens[$finalTokens[($newStackPtr - 1)]['code']]) === false ) { $lastNotEmptyToken = ($newStackPtr - 1); } @@ -601,14 +607,36 @@ protected function tokenize($string) echo PHP_EOL; } + /* + Before PHP 5.5, the yield keyword was tokenized as + T_STRING. So look for and change this token in + earlier versions. + */ + + if (PHP_VERSION_ID < 50500 + && $tokenIsArray === true + && $token[0] === T_STRING + && strtolower($token[1]) === 'yield' + && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + ) { + // Could still be a context sensitive keyword or "yield from" and potentially multi-line, + // so adjust the token stack in place. + $token[0] = T_YIELD; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr changed from T_STRING to T_YIELD".PHP_EOL; + } + } + /* Tokenize context sensitive keyword as string when it should be string. */ if ($tokenIsArray === true - && isset(Util\Tokens::$contextSensitiveKeywords[$token[0]]) === true + && isset(Tokens::$contextSensitiveKeywords[$token[0]]) === true && (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true - || $finalTokens[$lastNotEmptyToken]['content'] === '&') + || $finalTokens[$lastNotEmptyToken]['content'] === '&' + || $insideConstDeclaration === true) ) { if (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true) { $preserveKeyword = false; @@ -621,6 +649,23 @@ protected function tokenize($string) $preserveKeyword = true; } + // `new readonly class` should be preserved. + if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW + && strtolower($token[1]) === 'readonly' + ) { + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false + ) { + break; + } + } + + if (is_array($tokens[$i]) === true && $tokens[$i][0] === T_CLASS) { + $preserveKeyword = true; + } + } + // `new class extends` `new class implements` should be preserved if (($token[0] === T_EXTENDS || $token[0] === T_IMPLEMENTS) && $finalTokens[$lastNotEmptyToken]['code'] === T_CLASS @@ -635,7 +680,7 @@ protected function tokenize($string) break; } - if (isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true) { + if (isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true) { continue; } @@ -648,11 +693,35 @@ protected function tokenize($string) } }//end if + // Types in typed constants should not be touched, but the constant name should be. + if ((isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true + && $finalTokens[$lastNotEmptyToken]['code'] === T_CONST) + || $insideConstDeclaration === true + ) { + $preserveKeyword = true; + + // Find the next non-empty token. + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + break; + } + + if ($tokens[$i] === '=' || $tokens[$i] === ';') { + $preserveKeyword = false; + $insideConstDeclaration = false; + } + }//end if + if ($finalTokens[$lastNotEmptyToken]['content'] === '&') { $preserveKeyword = true; for ($i = ($lastNotEmptyToken - 1); $i >= 0; $i--) { - if (isset(Util\Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { continue; } @@ -666,7 +735,7 @@ protected function tokenize($string) if ($preserveKeyword === false) { if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($token[0]); + $type = Tokens::tokenName($token[0]); echo "\t\t* token $stackPtr changed from $type to T_STRING".PHP_EOL; } @@ -681,13 +750,106 @@ protected function tokenize($string) } }//end if + /* + Mark the start of a constant declaration to allow for handling keyword to T_STRING + convertion for constant names using reserved keywords. + */ + + if ($tokenIsArray === true && $token[0] === T_CONST) { + $insideConstDeclaration = true; + } + + /* + Close an open "inside constant declaration" marker when no keyword conversion was needed. + */ + + if ($insideConstDeclaration === true + && $tokenIsArray === false + && ($token[0] === '=' || $token[0] === ';') + ) { + $insideConstDeclaration = false; + } + + /* + Special case for `static` used as a function name, i.e. `static()`. + + Note: this may incorrectly change the static keyword directly before a DNF property type. + If so, this will be caught and corrected for in the additional processing. + */ + + if ($tokenIsArray === true + && $token[0] === T_STATIC + && $finalTokens[$lastNotEmptyToken]['code'] !== T_NEW + ) { + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + if ($tokens[$i][0] === '(') { + $finalTokens[$newStackPtr] = [ + 'code' => T_STRING, + 'type' => 'T_STRING', + 'content' => $token[1], + ]; + + $newStackPtr++; + continue 2; + } + + break; + } + }//end if + + /* + Prior to PHP 7.4, PHP didn't support stand-alone PHP open tags at the end of a file + (without a new line), so we need to make sure that the tokenization in PHPCS is consistent + cross-version PHP by retokenizing to T_OPEN_TAG. + */ + + if (PHP_VERSION_ID < 70400 + && $tokenIsArray === true + // PHP < 7.4 with short open tags off. + && (($stackPtr === ($numTokens - 1) + && $token[0] === T_INLINE_HTML + && stripos($token[1], ' T_OPEN_TAG, + 'type' => 'T_OPEN_TAG', + 'content' => $token[1], + ]; + } else { + $finalTokens[$newStackPtr] = [ + 'code' => T_OPEN_TAG, + 'type' => 'T_OPEN_TAG', + 'content' => $token[1].$tokens[($stackPtr + 1)][1], + ]; + + $stackPtr++; + } + + $newStackPtr++; + continue; + }//end if + /* Parse doc blocks into something that can be easily iterated over. */ if ($tokenIsArray === true && ($token[0] === T_DOC_COMMENT - || ($token[0] === T_COMMENT && strpos($token[1], '/**') === 0)) + || ($token[0] === T_COMMENT && strpos($token[1], '/**') === 0 && $token[1] !== '/**/')) ) { $commentTokens = $commentTokenizer->tokenizeString($token[1], $this->eolChar, $newStackPtr); foreach ($commentTokens as $commentToken) { @@ -750,6 +912,7 @@ protected function tokenize($string) && (isset($tokens[($stackPtr + 1)]) === true && is_array($tokens[($stackPtr + 1)]) === true && $tokens[($stackPtr + 1)][0] === T_STRING + && isset($tokens[($stackPtr + 1)][1][0], $tokens[($stackPtr + 1)][1][1]) === true && strtolower($tokens[($stackPtr + 1)][1][0]) === 'o' && $tokens[($stackPtr + 1)][1][1] !== '_') && preg_match('`^(o[0-7]+(?:_[0-7]+)?)([0-9_]*)$`i', $tokens[($stackPtr + 1)][1], $matches) === 1 @@ -1015,7 +1178,7 @@ protected function tokenize($string) // Get the next non-empty token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -1169,8 +1332,8 @@ protected function tokenize($string) } if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($token[0]); - $content = Util\Common::prepareForOutput($token[1]); + $type = Tokens::tokenName($token[0]); + $content = Common::prepareForOutput($token[1]); echo "\t\t* token $stackPtr split into individual tokens; was: $type => $content".PHP_EOL; } @@ -1233,7 +1396,7 @@ protected function tokenize($string) // Get the next non-empty token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -1246,7 +1409,7 @@ protected function tokenize($string) // Get the previous non-empty token. for ($j = ($stackPtr - 1); $j > 0; $j--) { if (is_array($tokens[$j]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$j][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$j][0]]) === false ) { break; } @@ -1269,7 +1432,7 @@ protected function tokenize($string) $tokens[$stackPtr][0] = T_PARAM_NAME; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($token[0]); + $type = Tokens::tokenName($token[0]); echo "\t\t* token $stackPtr changed from $type to T_PARAM_NAME".PHP_EOL; } @@ -1282,23 +1445,90 @@ protected function tokenize($string) "readonly" keyword for PHP < 8.1 */ - if (PHP_VERSION_ID < 80100 - && $tokenIsArray === true + if ($tokenIsArray === true && strtolower($token[1]) === 'readonly' - && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + && (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + || $finalTokens[$lastNotEmptyToken]['code'] === T_NEW) ) { // Get the next non-whitespace token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || $tokens[$i][0] !== T_WHITESPACE + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } } + $isReadonlyKeyword = false; + if (isset($tokens[$i]) === false || $tokens[$i] !== '(' ) { + $isReadonlyKeyword = true; + } else if ($tokens[$i] === '(') { + /* + * Skip over tokens which can be used in type declarations. + * At this point, the only token types which need to be taken into consideration + * as potential type declarations are identifier names, T_ARRAY, T_CALLABLE and T_NS_SEPARATOR + * and the union/intersection/dnf parentheses. + */ + + $foundDNFParens = 1; + $foundDNFPipe = 0; + + for (++$i; $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true) { + $tokenType = $tokens[$i][0]; + } else { + $tokenType = $tokens[$i]; + } + + if (isset(Tokens::$emptyTokens[$tokenType]) === true) { + continue; + } + + if ($tokenType === '|') { + ++$foundDNFPipe; + continue; + } + + if ($tokenType === ')') { + ++$foundDNFParens; + continue; + } + + if ($tokenType === '(') { + ++$foundDNFParens; + continue; + } + + if ($tokenType === T_STRING + || $tokenType === T_NAME_FULLY_QUALIFIED + || $tokenType === T_NAME_RELATIVE + || $tokenType === T_NAME_QUALIFIED + || $tokenType === T_ARRAY + || $tokenType === T_NAMESPACE + || $tokenType === T_NS_SEPARATOR + || $tokenType === T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG // PHP 8.0+. + || $tokenType === '&' // PHP < 8.0. + ) { + continue; + } + + // Reached the next token after. + if (($foundDNFParens % 2) === 0 + && $foundDNFPipe >= 1 + && ($tokenType === T_VARIABLE + || $tokenType === T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG) + ) { + $isReadonlyKeyword = true; + } + + break; + }//end for + }//end if + + if ($isReadonlyKeyword === true) { $finalTokens[$newStackPtr] = [ 'code' => T_READONLY, 'type' => 'T_READONLY', @@ -1306,85 +1536,186 @@ protected function tokenize($string) ]; $newStackPtr++; - continue; - } + // Also modify the original token stack so that + // future checks (like looking for T_NULLABLE) can + // detect the T_READONLY token more easily. + $tokens[$stackPtr][0] = T_READONLY; + $token[0] = T_READONLY; + + if (PHP_CODESNIFFER_VERBOSITY > 1 && $type !== T_READONLY) { + echo "\t\t* token $stackPtr changed from $type to T_READONLY".PHP_EOL; + } + } else { + $finalTokens[$newStackPtr] = [ + 'code' => T_STRING, + 'type' => 'T_STRING', + 'content' => $token[1], + ]; + $newStackPtr++; + + if (PHP_CODESNIFFER_VERBOSITY > 1 && $type !== T_STRING) { + echo "\t\t* token $stackPtr changed from $type to T_STRING".PHP_EOL; + } + }//end if + + continue; }//end if /* - Before PHP 7.0, the "yield from" was tokenized as + Before PHP 7.0, "yield from" was tokenized as T_YIELD, T_WHITESPACE and T_STRING. So look for and change this token in earlier versions. */ if (PHP_VERSION_ID < 70000 - && PHP_VERSION_ID >= 50500 && $tokenIsArray === true && $token[0] === T_YIELD && isset($tokens[($stackPtr + 1)]) === true && isset($tokens[($stackPtr + 2)]) === true && $tokens[($stackPtr + 1)][0] === T_WHITESPACE + && strpos($tokens[($stackPtr + 1)][1], $this->eolChar) === false && $tokens[($stackPtr + 2)][0] === T_STRING && strtolower($tokens[($stackPtr + 2)][1]) === 'from' ) { - // Could be multi-line, so adjust the token stack. - $token[0] = T_YIELD_FROM; - $token[1] .= $tokens[($stackPtr + 1)][1].$tokens[($stackPtr + 2)][1]; + // Single-line "yield from" with only whitespace between. + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => $token[1].$tokens[($stackPtr + 1)][1].$tokens[($stackPtr + 2)][1], + ]; if (PHP_CODESNIFFER_VERBOSITY > 1) { for ($i = ($stackPtr + 1); $i <= ($stackPtr + 2); $i++) { - $type = Util\Tokens::tokenName($tokens[$i][0]); - $content = Util\Common::prepareForOutput($tokens[$i][1]); + $type = Tokens::tokenName($tokens[$i][0]); + $content = Common::prepareForOutput($tokens[$i][1]); echo "\t\t* token $i merged into T_YIELD_FROM; was: $type => $content".PHP_EOL; } } - $tokens[($stackPtr + 1)] = null; - $tokens[($stackPtr + 2)] = null; - } - - /* - Before PHP 5.5, the yield keyword was tokenized as - T_STRING. So look for and change this token in - earlier versions. - Checks also if it is just "yield" or "yield from". - */ + $newStackPtr++; + $stackPtr += 2; - if (PHP_VERSION_ID < 50500 + continue; + } else if (PHP_VERSION_ID < 80300 && $tokenIsArray === true && $token[0] === T_STRING - && strtolower($token[1]) === 'yield' - && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + && strtolower($token[1]) === 'from' + && $finalTokens[$lastNotEmptyToken]['code'] === T_YIELD ) { - if (isset($tokens[($stackPtr + 1)]) === true - && isset($tokens[($stackPtr + 2)]) === true - && $tokens[($stackPtr + 1)][0] === T_WHITESPACE - && $tokens[($stackPtr + 2)][0] === T_STRING - && strtolower($tokens[($stackPtr + 2)][1]) === 'from' - ) { - // Could be multi-line, so just just the token stack. - $token[0] = T_YIELD_FROM; - $token[1] .= $tokens[($stackPtr + 1)][1].$tokens[($stackPtr + 2)][1]; + /* + Before PHP 8.3, if there was a comment between the "yield" and "from" keywords, + it was tokenized as T_YIELD, T_WHITESPACE, T_COMMENT... and T_STRING. + We want to keep the tokenization of the tokens between, but need to change the + `T_YIELD` and `T_STRING` (from) keywords to `T_YIELD_FROM. + */ - if (PHP_CODESNIFFER_VERBOSITY > 1) { - for ($i = ($stackPtr + 1); $i <= ($stackPtr + 2); $i++) { - $type = Util\Tokens::tokenName($tokens[$i][0]); - $content = Util\Common::prepareForOutput($tokens[$i][1]); - echo "\t\t* token $i merged into T_YIELD_FROM; was: $type => $content".PHP_EOL; + $finalTokens[$lastNotEmptyToken]['code'] = T_YIELD_FROM; + $finalTokens[$lastNotEmptyToken]['type'] = 'T_YIELD_FROM'; + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => $token[1], + ]; + $newStackPtr++; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $lastNotEmptyToken (new stack) changed into T_YIELD_FROM; was: T_YIELD".PHP_EOL; + echo "\t\t* token $stackPtr changed into T_YIELD_FROM; was: T_STRING".PHP_EOL; + } + + continue; + } else if (PHP_VERSION_ID >= 70000 + && $tokenIsArray === true + && $token[0] === T_YIELD_FROM + && strpos($token[1], $this->eolChar) !== false + && preg_match('`^yield\s+from$`i', $token[1]) === 1 + ) { + /* + In PHP 7.0+, a multi-line "yield from" (without comment) tokenizes as a single + T_YIELD_FROM token, but we want to split it and tokenize the whitespace + separately for consistency. + */ + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => substr($token[1], 0, 5), + ]; + $newStackPtr++; + + $tokenLines = explode($this->eolChar, substr($token[1], 5, -4)); + $numLines = count($tokenLines); + $newToken = [ + 'type' => 'T_WHITESPACE', + 'code' => T_WHITESPACE, + 'content' => '', + ]; + + foreach ($tokenLines as $i => $line) { + $newToken['content'] = $line; + if ($i === ($numLines - 1)) { + if ($line === '') { + break; } + } else { + $newToken['content'] .= $this->eolChar; } - $tokens[($stackPtr + 1)] = null; - $tokens[($stackPtr + 2)] = null; - } else { - $newToken = []; - $newToken['code'] = T_YIELD; - $newToken['type'] = 'T_YIELD'; - $newToken['content'] = $token[1]; $finalTokens[$newStackPtr] = $newToken; - $newStackPtr++; - continue; - }//end if + } + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => substr($token[1], -4), + ]; + $newStackPtr++; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr split into 'yield', one or more whitespace tokens and 'from'".PHP_EOL; + } + + continue; + } else if (PHP_VERSION_ID >= 80300 + && $tokenIsArray === true + && $token[0] === T_YIELD_FROM + && preg_match('`^yield[ \t]+from$`i', $token[1]) !== 1 + && stripos($token[1], 'yield') === 0 + ) { + /* + Since PHP 8.3, "yield from" allows for comments and will + swallow the comment in the `T_YIELD_FROM` token. + We need to split this up to allow for sniffs handling comments. + */ + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => substr($token[1], 0, 5), + ]; + $newStackPtr++; + + $yieldFromSubtokens = @token_get_all(" T_YIELD_FROM, + 1 => substr($token[1], -4), + ]; + + // Inject the new tokens into the token stack. + array_splice($tokens, ($stackPtr + 1), 0, $yieldFromSubtokens); + $numTokens = count($tokens); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr split into parts (yield from with comment)".PHP_EOL; + } + + unset($yieldFromSubtokens); + continue; }//end if /* @@ -1597,7 +1928,7 @@ protected function tokenize($string) || (stripos($newContent, '0b') === 0 && bindec(str_replace('_', '', $newContent)) > PHP_INT_MAX) || (stripos($newContent, '0o') === 0 && octdec(str_replace('_', '', $newContent)) > PHP_INT_MAX) || (stripos($newContent, '0x') !== 0 - && stripos($newContent, 'e') !== false || strpos($newContent, '.') !== false) + && (stripos($newContent, 'e') !== false || strpos($newContent, '.') !== false)) || (strpos($newContent, '0') === 0 && stripos($newContent, '0x') !== 0 && stripos($newContent, '0b') !== 0 && octdec(str_replace('_', '', $newContent)) > PHP_INT_MAX) || (strpos($newContent, '0') !== 0 && str_replace('_', '', $newContent) > PHP_INT_MAX)) @@ -1607,7 +1938,7 @@ protected function tokenize($string) $newToken = []; $newToken['code'] = $newType; - $newToken['type'] = Util\Tokens::tokenName($newType); + $newToken['type'] = Tokens::tokenName($newType); $newToken['content'] = $newContent; $finalTokens[$newStackPtr] = $newToken; @@ -1631,7 +1962,7 @@ protected function tokenize($string) ) { $isMatch = false; for ($x = ($stackPtr + 1); $x < $numTokens; $x++) { - if (isset($tokens[$x][0], Util\Tokens::$emptyTokens[$tokens[$x][0]]) === true) { + if (isset($tokens[$x][0], Tokens::$emptyTokens[$tokens[$x][0]]) === true) { continue; } @@ -1696,7 +2027,7 @@ protected function tokenize($string) } if (is_array($tokens[$x]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$x][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$x][0]]) === false ) { // Non-empty, non-comma content. break; @@ -1739,6 +2070,20 @@ protected function tokenize($string) $newToken = []; $newToken['content'] = '?'; + // For typed constants, we only need to check the token before the ? to be sure. + if ($finalTokens[$lastNotEmptyToken]['code'] === T_CONST) { + $newToken['code'] = T_NULLABLE; + $newToken['type'] = 'T_NULLABLE'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr changed from ? to T_NULLABLE".PHP_EOL; + } + + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + continue; + } + /* * Check if the next non-empty token is one of the tokens which can be used * in type declarations. If not, it's definitely a ternary. @@ -1755,7 +2100,7 @@ protected function tokenize($string) $tokenType = $tokens[$i]; } - if (isset(Util\Tokens::$emptyTokens[$tokenType]) === true) { + if (isset(Tokens::$emptyTokens[$tokenType]) === true) { continue; } @@ -1824,7 +2169,7 @@ protected function tokenize($string) } if ($prevNonEmpty === null - && isset(Util\Tokens::$emptyTokens[$tokenType]) === false + && isset(Tokens::$emptyTokens[$tokenType]) === false ) { // Found the previous non-empty token. if ($tokenType === ':' || $tokenType === ',' || $tokenType === T_ATTRIBUTE_END) { @@ -1843,8 +2188,9 @@ protected function tokenize($string) if ($tokenType === T_FUNCTION || $tokenType === T_FN - || isset(Util\Tokens::$methodPrefixes[$tokenType]) === true + || isset(Tokens::$methodPrefixes[$tokenType]) === true || $tokenType === T_VAR + || $tokenType === T_READONLY ) { if (PHP_CODESNIFFER_VERBOSITY > 1) { echo "\t\t* token $stackPtr changed from ? to T_NULLABLE".PHP_EOL; @@ -1865,7 +2211,7 @@ protected function tokenize($string) break; } - if (isset(Util\Tokens::$emptyTokens[$tokenType]) === false) { + if (isset(Tokens::$emptyTokens[$tokenType]) === false) { $lastSeenNonEmpty = $tokenType; } }//end for @@ -1888,7 +2234,7 @@ protected function tokenize($string) && $token[0] !== T_STRING && $token[0] !== T_VARIABLE && $token[0] !== T_DOLLAR - && isset(Util\Tokens::$emptyTokens[$token[0]]) === false + && isset(Tokens::$emptyTokens[$token[0]]) === false ) { $newToken = []; $newToken['code'] = T_STRING; @@ -1948,11 +2294,11 @@ function return types. We want to keep the parenthesis map clean, if ($parenthesisCloser !== false) { for ($x = ($parenthesisCloser + 1); $x < $numTokens; $x++) { if (is_array($tokens[$x]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$x][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$x][0]]) === false ) { // Non-empty content. if (is_array($tokens[$x]) === true && $tokens[$x][0] === T_USE) { - // Found a use statements, so search ahead for the closing parenthesis. + // Found a use statement, so search ahead for the closing parenthesis. for ($x += 1; $x < $numTokens; $x++) { if (is_array($tokens[$x]) === false && $tokens[$x] === ')') { continue(2); @@ -1971,7 +2317,7 @@ function return types. We want to keep the parenthesis map clean, // Find the start of the return type. for ($x += 1; $x < $numTokens; $x++) { if (is_array($tokens[$x]) === true - && isset(Util\Tokens::$emptyTokens[$tokens[$x][0]]) === true + && isset(Tokens::$emptyTokens[$tokens[$x][0]]) === true ) { // Whitespace or comments before the return type. continue; @@ -2083,7 +2429,7 @@ function return types. We want to keep the parenthesis map clean, $tokenLines = explode($this->eolChar, $token[1]); $numLines = count($tokenLines); $newToken = [ - 'type' => Util\Tokens::tokenName($token[0]), + 'type' => Tokens::tokenName($token[0]), 'code' => $token[0], 'content' => '', ]; @@ -2103,38 +2449,83 @@ function return types. We want to keep the parenthesis map clean, } } else { // Some T_STRING tokens should remain that way due to their context. - if ($tokenIsArray === true - && $token[0] === T_STRING - && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true - ) { - // Special case for syntax like: return new self/new parent - // where self/parent should not be a string. - $tokenContentLower = strtolower($token[1]); - if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW - && ($tokenContentLower === 'self' || $tokenContentLower === 'parent') + if ($tokenIsArray === true && $token[0] === T_STRING) { + $preserveTstring = false; + + // True/false/parent/self/static in typed constants should be fixed to their own token, + // but the constant name should not be. + if ((isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true + && $finalTokens[$lastNotEmptyToken]['code'] === T_CONST) + || $insideConstDeclaration === true ) { - $finalTokens[$newStackPtr] = [ - 'content' => $token[1], - ]; - if ($tokenContentLower === 'self') { - $finalTokens[$newStackPtr]['code'] = T_SELF; - $finalTokens[$newStackPtr]['type'] = 'T_SELF'; + // Find the next non-empty token. + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + break; + } + + if ($tokens[$i] === '=') { + $preserveTstring = true; + $insideConstDeclaration = false; } + } else if (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true + && $finalTokens[$lastNotEmptyToken]['code'] !== T_CONST + ) { + $preserveTstring = true; + + // Special case for syntax like: return new self/new parent + // where self/parent should not be a string. + $tokenContentLower = strtolower($token[1]); + if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW + && ($tokenContentLower === 'self' || $tokenContentLower === 'parent') + ) { + $preserveTstring = false; + } + } else if ($finalTokens[$lastNotEmptyToken]['content'] === '&') { + // Function names for functions declared to return by reference. + for ($i = ($lastNotEmptyToken - 1); $i >= 0; $i--) { + if (isset(Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { + continue; + } - if ($tokenContentLower === 'parent') { - $finalTokens[$newStackPtr]['code'] = T_PARENT; - $finalTokens[$newStackPtr]['type'] = 'T_PARENT'; + if ($finalTokens[$i]['code'] === T_FUNCTION) { + $preserveTstring = true; + } + + break; } } else { + // Keywords with special PHPCS token when used as a function call. + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + if ($tokens[$i][0] === '(') { + $preserveTstring = true; + } + + break; + } + }//end if + + if ($preserveTstring === true) { $finalTokens[$newStackPtr] = [ - 'content' => $token[1], 'code' => T_STRING, 'type' => 'T_STRING', + 'content' => $token[1], ]; - } - $newStackPtr++; - continue; + $newStackPtr++; + continue; + } }//end if $newToken = null; @@ -2169,7 +2560,7 @@ function return types. We want to keep the parenthesis map clean, // Get the previous non-empty token. for ($i = ($stackPtr - 1); $i > 0; $i--) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -2249,11 +2640,12 @@ function return types. We want to keep the parenthesis map clean, if (is_array($tokens[$i]) === false && ($tokens[$i] === ';' - || $tokens[$i] === '{') + || $tokens[$i] === '{' + || $tokens[$i] === '}') ) { break; } - } + }//end for }//end if if ($isInlineIf === true) { @@ -2275,7 +2667,7 @@ function return types. We want to keep the parenthesis map clean, if ($newToken['code'] === T_ARRAY) { for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { // Non-empty content. break; @@ -2360,7 +2752,9 @@ protected function processAdditional() $this->createAttributesNestingMap(); - $numTokens = count($this->tokens); + $numTokens = count($this->tokens); + $lastSeenTypeToken = $numTokens; + for ($i = ($numTokens - 1); $i >= 0; $i--) { // Check for any unset scope conditions due to alternate IF/ENDIF syntax. if (isset($this->tokens[$i]['scope_opener']) === true @@ -2377,7 +2771,7 @@ protected function processAdditional() if (isset($this->tokens[$i]['scope_opener']) === true) { for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false && $this->tokens[$x]['code'] !== T_BITWISE_AND ) { break; @@ -2413,7 +2807,7 @@ protected function processAdditional() */ for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { break; } } @@ -2464,7 +2858,7 @@ protected function processAdditional() } else if ($this->tokens[$i]['code'] === T_FN && isset($this->tokens[($i + 1)]) === true) { // Possible arrow function. for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false && $this->tokens[$x]['code'] !== T_BITWISE_AND ) { // Non-whitespace content. @@ -2472,22 +2866,29 @@ protected function processAdditional() } } - if (isset($this->tokens[$x]) === true && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) { - $ignore = Util\Tokens::$emptyTokens; + if (isset($this->tokens[$x]) === true + && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS + && isset($this->tokens[$x]['parenthesis_closer']) === true + ) { + $ignore = Tokens::$emptyTokens; $ignore += [ - T_ARRAY => T_ARRAY, - T_CALLABLE => T_CALLABLE, - T_COLON => T_COLON, - T_NAMESPACE => T_NAMESPACE, - T_NS_SEPARATOR => T_NS_SEPARATOR, - T_NULL => T_NULL, - T_NULLABLE => T_NULLABLE, - T_PARENT => T_PARENT, - T_SELF => T_SELF, - T_STATIC => T_STATIC, - T_STRING => T_STRING, - T_TYPE_UNION => T_TYPE_UNION, - T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_ARRAY => T_ARRAY, + T_CALLABLE => T_CALLABLE, + T_COLON => T_COLON, + T_NAMESPACE => T_NAMESPACE, + T_NS_SEPARATOR => T_NS_SEPARATOR, + T_NULL => T_NULL, + T_TRUE => T_TRUE, + T_FALSE => T_FALSE, + T_NULLABLE => T_NULLABLE, + T_PARENT => T_PARENT, + T_SELF => T_SELF, + T_STATIC => T_STATIC, + T_STRING => T_STRING, + T_TYPE_UNION => T_TYPE_UNION, + T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS, + T_TYPE_CLOSE_PARENTHESIS => T_TYPE_CLOSE_PARENTHESIS, ]; $closer = $this->tokens[$x]['parenthesis_closer']; @@ -2532,7 +2933,7 @@ protected function processAdditional() } for ($lastNonEmpty = ($scopeCloser - 1); $lastNonEmpty > $arrow; $lastNonEmpty--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { $scopeCloser = $lastNonEmpty; break 2; } @@ -2547,7 +2948,7 @@ protected function processAdditional() && $this->tokens[$scopeCloser]['bracket_opener'] < $arrow)) ) { for ($lastNonEmpty = ($scopeCloser - 1); $lastNonEmpty > $arrow; $lastNonEmpty--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { $scopeCloser = $lastNonEmpty; break; } @@ -2646,7 +3047,7 @@ protected function processAdditional() }//end if }//end if - // If after all that, the extra tokens are not set, this is not an arrow function. + // If after all that, the extra tokens are not set, this is not a (valid) arrow function. if (isset($this->tokens[$i]['scope_closer']) === false) { if (PHP_CODESNIFFER_VERBOSITY > 1) { $line = $this->tokens[$i]['line']; @@ -2676,7 +3077,7 @@ protected function processAdditional() T_CONSTANT_ENCAPSED_STRING => T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_QUOTED_STRING => T_DOUBLE_QUOTED_STRING, ]; - $allowed += Util\Tokens::$magicConstants; + $allowed += Tokens::$magicConstants; for ($x = ($i - 1); $x >= 0; $x--) { // If we hit a scope opener, the statement has ended @@ -2687,11 +3088,11 @@ protected function processAdditional() break; } - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { // Allow for control structures without braces. if (($this->tokens[$x]['code'] === T_CLOSE_PARENTHESIS && isset($this->tokens[$x]['parenthesis_owner']) === true - && isset(Util\Tokens::$scopeOpeners[$this->tokens[$this->tokens[$x]['parenthesis_owner']]['code']]) === true) + && isset(Tokens::$scopeOpeners[$this->tokens[$this->tokens[$x]['parenthesis_owner']]['code']]) === true) || isset($allowed[$this->tokens[$x]['code']]) === false ) { $isShortArray = true; @@ -2753,7 +3154,7 @@ protected function processAdditional() T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_DOUBLE_ARROW => T_DOUBLE_ARROW, ]; - $searchFor += Util\Tokens::$scopeOpeners; + $searchFor += Tokens::$scopeOpeners; for ($x = ($this->tokens[$i]['scope_opener'] + 1); $x < $this->tokens[$i]['scope_closer']; $x++) { if (isset($searchFor[$this->tokens[$x]['code']]) === false) { @@ -2790,10 +3191,20 @@ protected function processAdditional() continue; } else if ($this->tokens[$i]['code'] === T_BITWISE_OR || $this->tokens[$i]['code'] === T_BITWISE_AND + || $this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS ) { + if ($lastSeenTypeToken < $i) { + // We've already examined this code to check if it is a type declaration and concluded it wasn't. + // No need to do it again. + continue; + } + /* Convert "|" to T_TYPE_UNION or leave as T_BITWISE_OR. Convert "&" to T_TYPE_INTERSECTION or leave as T_BITWISE_AND. + Convert "(" and ")" to T_TYPE_(OPEN|CLOSE)_PARENTHESIS or leave as T_(OPEN|CLOSE)_PARENTHESIS. + + All type related tokens will be converted in one go as soon as this section is hit. */ $allowed = [ @@ -2803,25 +3214,28 @@ protected function processAdditional() T_PARENT => T_PARENT, T_STATIC => T_STATIC, T_FALSE => T_FALSE, + T_TRUE => T_TRUE, T_NULL => T_NULL, T_NAMESPACE => T_NAMESPACE, T_NS_SEPARATOR => T_NS_SEPARATOR, ]; - $suspectedType = null; - $typeTokenCount = 0; + $suspectedType = null; + $typeTokenCountAfter = 0; for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } if (isset($allowed[$this->tokens[$x]['code']]) === true) { - ++$typeTokenCount; + ++$typeTokenCountAfter; continue; } - if ($typeTokenCount > 0 + if (($typeTokenCountAfter > 0 + || ($this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS + && isset($this->tokens[$i]['parenthesis_owner']) === false)) && ($this->tokens[$x]['code'] === T_BITWISE_AND || $this->tokens[$x]['code'] === T_ELLIPSIS) ) { @@ -2852,32 +3266,104 @@ protected function processAdditional() && $this->tokens[$this->tokens[$x]['scope_condition']]['code'] === T_FUNCTION ) { $suspectedType = 'return'; + break; + } + + if ($this->tokens[$x]['code'] === T_EQUAL) { + // Possible constant declaration, the `T_STRING` name will have been skipped over already. + $suspectedType = 'constant'; + break; } break; }//end for - if ($typeTokenCount === 0 || isset($suspectedType) === false) { - // Definitely not a union or intersection type, move on. + if (($typeTokenCountAfter === 0 + && ($this->tokens[$i]['code'] !== T_CLOSE_PARENTHESIS + || isset($this->tokens[$i]['parenthesis_owner']) === true)) + || isset($suspectedType) === false + ) { + // Definitely not a union, intersection or DNF type, move on. continue; } - $typeTokenCount = 0; - $typeOperators = [$i]; - $confirmed = false; + if ($suspectedType === 'property or parameter') { + unset($allowed[T_STATIC]); + } + + $typeTokenCountBefore = 0; + $typeOperators = [$i]; + $parenthesesCount = 0; + $confirmed = false; + $maybeNullable = null; + + if ($this->tokens[$i]['code'] === T_OPEN_PARENTHESIS || $this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS) { + ++$parenthesesCount; + } for ($x = ($i - 1); $x >= 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } + if ($suspectedType === 'property or parameter' + && $this->tokens[$x]['code'] === T_STRING + && strtolower($this->tokens[$x]['content']) === 'static' + ) { + // Static keyword followed directly by an open parenthesis for a DNF type. + // This token should be T_STATIC and was incorrectly identified as a function call before. + $this->tokens[$x]['code'] = T_STATIC; + $this->tokens[$x]['type'] = 'T_STATIC'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$x]['line']; + echo "\t* token $x on line $line changed back from T_STRING to T_STATIC".PHP_EOL; + } + } + + if ($suspectedType === 'property or parameter' + && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS + ) { + // We need to prevent the open parenthesis for a function/fn declaration from being retokenized + // to T_TYPE_OPEN_PARENTHESIS if this is the first parameter in the declaration. + if (isset($this->tokens[$x]['parenthesis_owner']) === true + && $this->tokens[$this->tokens[$x]['parenthesis_owner']]['code'] === T_FUNCTION + ) { + $confirmed = true; + break; + } else { + // This may still be an arrow function which hasn't been handled yet. + for ($y = ($x - 1); $y > 0; $y--) { + if (isset(Tokens::$emptyTokens[$this->tokens[$y]['code']]) === false + && $this->tokens[$y]['code'] !== T_BITWISE_AND + ) { + // Non-whitespace content. + break; + } + } + + if ($this->tokens[$y]['code'] === T_FN) { + $confirmed = true; + break; + } + } + }//end if + if (isset($allowed[$this->tokens[$x]['code']]) === true) { - ++$typeTokenCount; + ++$typeTokenCountBefore; continue; } - // Union and intersection types can't use the nullable operator, but be tolerant to parse errors. - if ($typeTokenCount > 0 && $this->tokens[$x]['code'] === T_NULLABLE) { + // Union, intersection and DNF types can't use the nullable operator, but be tolerant to parse errors. + if (($typeTokenCountBefore > 0 + || ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS && isset($this->tokens[$x]['parenthesis_owner']) === false)) + && ($this->tokens[$x]['code'] === T_NULLABLE + || $this->tokens[$x]['code'] === T_INLINE_THEN) + ) { + if ($this->tokens[$x]['code'] === T_INLINE_THEN) { + $maybeNullable = $x; + } + continue; } @@ -2886,15 +3372,64 @@ protected function processAdditional() continue; } + if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS || $this->tokens[$x]['code'] === T_CLOSE_PARENTHESIS) { + ++$parenthesesCount; + $typeOperators[] = $x; + continue; + } + if ($suspectedType === 'return' && $this->tokens[$x]['code'] === T_COLON) { + // Make sure this is the colon for a return type. + for ($y = ($x - 1); $y > 0; $y--) { + if (isset(Tokens::$emptyTokens[$this->tokens[$y]['code']]) === false) { + break; + } + } + + if ($this->tokens[$y]['code'] !== T_CLOSE_PARENTHESIS) { + // Definitely not a union, intersection or DNF return type, move on. + continue 2; + } + + if (isset($this->tokens[$y]['parenthesis_owner']) === true) { + if ($this->tokens[$this->tokens[$y]['parenthesis_owner']]['code'] === T_FUNCTION + || $this->tokens[$this->tokens[$y]['parenthesis_owner']]['code'] === T_CLOSURE + || $this->tokens[$this->tokens[$y]['parenthesis_owner']]['code'] === T_FN + ) { + $confirmed = true; + } + + break; + } + + // Arrow functions may not have the parenthesis_owner set correctly yet. + // Closure use tokens won't be parentheses owners until PHPCS 4.0. + if (isset($this->tokens[$y]['parenthesis_opener']) === true) { + for ($z = ($this->tokens[$y]['parenthesis_opener'] - 1); $z > 0; $z--) { + if (isset(Tokens::$emptyTokens[$this->tokens[$z]['code']]) === false) { + break; + } + } + + if ($this->tokens[$z]['code'] === T_FN || $this->tokens[$z]['code'] === T_USE) { + $confirmed = true; + } + } + + break; + }//end if + + if ($suspectedType === 'constant' && $this->tokens[$x]['code'] === T_CONST) { $confirmed = true; break; } if ($suspectedType === 'property or parameter' - && (isset(Util\Tokens::$scopeModifiers[$this->tokens[$x]['code']]) === true + && (isset(Tokens::$scopeModifiers[$this->tokens[$x]['code']]) === true || $this->tokens[$x]['code'] === T_VAR - || $this->tokens[$x]['code'] === T_READONLY) + || $this->tokens[$x]['code'] === T_STATIC + || $this->tokens[$x]['code'] === T_READONLY + || $this->tokens[$x]['code'] === T_FINAL) ) { // This will also confirm constructor property promotion parameters, but that's fine. $confirmed = true; @@ -2903,6 +3438,9 @@ protected function processAdditional() break; }//end for + // Remember the last token we examined as part of the (non-)"type declaration". + $lastSeenTypeToken = $x; + if ($confirmed === false && $suspectedType === 'property or parameter' && isset($this->tokens[$i]['nested_parenthesis']) === true @@ -2919,7 +3457,7 @@ protected function processAdditional() // had additional processing done. if (isset($this->tokens[$last]['parenthesis_opener']) === true) { for ($x = ($this->tokens[$last]['parenthesis_opener'] - 1); $x >= 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } @@ -2928,7 +3466,7 @@ protected function processAdditional() if ($this->tokens[$x]['code'] === T_FN) { for (--$x; $x >= 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true || $this->tokens[$x]['code'] === T_BITWISE_AND ) { continue; @@ -2947,8 +3485,8 @@ protected function processAdditional() unset($parens, $last); }//end if - if ($confirmed === false) { - // Not a union or intersection type after all, move on. + if ($confirmed === false || ($parenthesesCount % 2) !== 0) { + // Not a (valid) union, intersection or DNF type after all, move on. continue; } @@ -2961,7 +3499,7 @@ protected function processAdditional() $line = $this->tokens[$x]['line']; echo "\t* token $x on line $line changed from T_BITWISE_OR to T_TYPE_UNION".PHP_EOL; } - } else { + } else if ($this->tokens[$x]['code'] === T_BITWISE_AND) { $this->tokens[$x]['code'] = T_TYPE_INTERSECTION; $this->tokens[$x]['type'] = 'T_TYPE_INTERSECTION'; @@ -2969,13 +3507,39 @@ protected function processAdditional() $line = $this->tokens[$x]['line']; echo "\t* token $x on line $line changed from T_BITWISE_AND to T_TYPE_INTERSECTION".PHP_EOL; } + } else if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) { + $this->tokens[$x]['code'] = T_TYPE_OPEN_PARENTHESIS; + $this->tokens[$x]['type'] = 'T_TYPE_OPEN_PARENTHESIS'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$x]['line']; + echo "\t* token $x on line $line changed from T_OPEN_PARENTHESIS to T_TYPE_OPEN_PARENTHESIS".PHP_EOL; + } + } else if ($this->tokens[$x]['code'] === T_CLOSE_PARENTHESIS) { + $this->tokens[$x]['code'] = T_TYPE_CLOSE_PARENTHESIS; + $this->tokens[$x]['type'] = 'T_TYPE_CLOSE_PARENTHESIS'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$x]['line']; + echo "\t* token $x on line $line changed from T_CLOSE_PARENTHESIS to T_TYPE_CLOSE_PARENTHESIS".PHP_EOL; + } + }//end if + }//end foreach + + if (isset($maybeNullable) === true) { + $this->tokens[$maybeNullable]['code'] = T_NULLABLE; + $this->tokens[$maybeNullable]['type'] = 'T_NULLABLE'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$maybeNullable]['line']; + echo "\t* token $maybeNullable on line $line changed from T_INLINE_THEN to T_NULLABLE".PHP_EOL; } } continue; } else if ($this->tokens[$i]['code'] === T_STATIC) { for ($x = ($i - 1); $x > 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { break; } } @@ -2995,14 +3559,16 @@ protected function processAdditional() || $this->tokens[$i]['code'] === T_FALSE || $this->tokens[$i]['code'] === T_NULL ) { - for ($x = ($i + 1); $i < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + for ($x = ($i + 1); $x < $numTokens; $x++) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { // Non-whitespace content. break; } } - if (isset($this->tstringContexts[$this->tokens[$x]['code']]) === true) { + if ($x !== $numTokens + && isset($this->tstringContexts[$this->tokens[$x]['code']]) === true + ) { if (PHP_CODESNIFFER_VERBOSITY > 1) { $line = $this->tokens[$i]['line']; $type = $this->tokens[$i]['type']; @@ -3030,7 +3596,7 @@ protected function processAdditional() // opening this case statement and the opener and closer are // probably set incorrectly. for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { // Non-whitespace content. break; } @@ -3134,14 +3700,14 @@ protected function processAdditional() $type = $this->tokens[$x]['type']; $oldConds = ''; foreach ($oldConditions as $condition) { - $oldConds .= Util\Tokens::tokenName($condition).','; + $oldConds .= Tokens::tokenName($condition).','; } $oldConds = rtrim($oldConds, ','); $newConds = ''; foreach ($this->tokens[$x]['conditions'] as $condition) { - $newConds .= Util\Tokens::tokenName($condition).','; + $newConds .= Tokens::tokenName($condition).','; } $newConds = rtrim($newConds, ','); @@ -3229,7 +3795,7 @@ public static function standardiseToken($token) } else { $newToken = [ 'code' => $token[0], - 'type' => Util\Tokens::tokenName($token[0]), + 'type' => Tokens::tokenName($token[0]), ]; self::$resolveTokenCache[$token[0]] = $newToken; @@ -3353,10 +3919,10 @@ public static function resolveSimpleToken($token) * Finds a "closer" token (closing parenthesis or square bracket for example) * Handle parenthesis balancing while searching for closing token * - * @param array $tokens The list of tokens to iterate searching the closing token (as returned by token_get_all) - * @param int $start The starting position - * @param string|string[] $openerTokens The opening character - * @param string $closerChar The closing character + * @param array $tokens The list of tokens to iterate searching the closing token (as returned by token_get_all). + * @param int $start The starting position. + * @param string|string[] $openerTokens The opening character. + * @param string $closerChar The closing character. * * @return int|null The position of the closing token, if found. NULL otherwise. */ @@ -3390,8 +3956,8 @@ private function findCloser(array &$tokens, $start, $openerTokens, $closerChar) * PHP 8 attributes parser for PHP < 8 * Handles single-line and multiline attributes. * - * @param array $tokens The original array of tokens (as returned by token_get_all) - * @param int $stackPtr The current position in token array + * @param array $tokens The original array of tokens (as returned by token_get_all). + * @param int $stackPtr The current position in token array. * * @return array|null The array of parsed attribute tokens */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php index 0e00bf7f2..b22de1cc1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php @@ -4,13 +4,14 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; use PHP_CodeSniffer\Exceptions\TokenizerException; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\Tokens; abstract class Tokenizer { @@ -27,7 +28,7 @@ abstract class Tokenizer * * @var string */ - protected $eolChar = []; + protected $eolChar = ''; /** * A token-based representation of the content. @@ -60,7 +61,7 @@ abstract class Tokenizer /** * Known lengths of tokens. * - * @var array + * @var array */ public $knownLengths = []; @@ -75,9 +76,9 @@ abstract class Tokenizer /** * Initialise and run the tokenizer. * - * @param string $content The content to tokenize, - * @param \PHP_CodeSniffer\Config | null $config The config data for the run. - * @param string $eolChar The EOL char used in the content. + * @param string $content The content to tokenize. + * @param \PHP_CodeSniffer\Config|null $config The config data for the run. + * @param string $eolChar The EOL char used in the content. * * @return void * @throws \PHP_CodeSniffer\Exceptions\TokenizerException If the file appears to be minified. @@ -192,11 +193,14 @@ private function createPositionMap() T_DOC_COMMENT_STRING => true, T_CONSTANT_ENCAPSED_STRING => true, T_DOUBLE_QUOTED_STRING => true, + T_START_HEREDOC => true, + T_START_NOWDOC => true, T_HEREDOC => true, T_NOWDOC => true, T_END_HEREDOC => true, T_END_NOWDOC => true, T_INLINE_HTML => true, + T_YIELD_FROM => true, ]; $this->numTokens = count($this->tokens); @@ -617,7 +621,7 @@ public function replaceTabsInToken(&$token, $prefix=' ', $padding=' ', $tabWidth if ($content !== '') { $newContent .= $content; if ($checkEncoding === true) { - // Not using the default encoding, so take a bit more care. + // Not using ASCII encoding, so take a bit more care. $oldLevel = error_reporting(); error_reporting(0); $contentLength = iconv_strlen($content, $this->config->encoding); @@ -680,7 +684,7 @@ private function createTokenMap() Parenthesis mapping. */ - if (isset(Util\Tokens::$parenthesisOpeners[$this->tokens[$i]['code']]) === true) { + if (isset(Tokens::$parenthesisOpeners[$this->tokens[$i]['code']]) === true) { $this->tokens[$i]['parenthesis_opener'] = null; $this->tokens[$i]['parenthesis_closer'] = null; $this->tokens[$i]['parenthesis_owner'] = $i; @@ -896,7 +900,7 @@ private function createScopeMap() if (isset($this->scopeOpeners[$this->tokens[$i]['code']]) === true) { if (PHP_CODESNIFFER_VERBOSITY > 1) { $type = $this->tokens[$i]['type']; - $content = Util\Common::prepareForOutput($this->tokens[$i]['content']); + $content = Common::prepareForOutput($this->tokens[$i]['content']); echo "\tStart scope map at $i:$type => $content".PHP_EOL; } @@ -958,7 +962,7 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) if (PHP_CODESNIFFER_VERBOSITY > 1) { $type = $this->tokens[$i]['type']; $line = $this->tokens[$i]['line']; - $content = Util\Common::prepareForOutput($this->tokens[$i]['content']); + $content = Common::prepareForOutput($this->tokens[$i]['content']); echo str_repeat("\t", $depth); echo "Process token $i on line $line ["; @@ -1314,13 +1318,13 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) // Make sure this is actually an opener and not a // string offset (e.g., $var{0}). for ($x = ($i - 1); $x > 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } else { // If the first non-whitespace/comment token looks like this // brace is a string offset, or this brace is mid-way through // a new statement, it isn't a scope opener. - $disallowed = Util\Tokens::$assignmentTokens; + $disallowed = Tokens::$assignmentTokens; $disallowed += [ T_DOLLAR => true, T_VARIABLE => true, @@ -1388,7 +1392,7 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) } else if ($tokenType === T_OPEN_PARENTHESIS) { if (isset($this->tokens[$i]['parenthesis_owner']) === true) { $owner = $this->tokens[$i]['parenthesis_owner']; - if (isset(Util\Tokens::$scopeOpeners[$this->tokens[$owner]['code']]) === true + if (isset(Tokens::$scopeOpeners[$this->tokens[$owner]['code']]) === true && isset($this->tokens[$i]['parenthesis_closer']) === true ) { // If we get into here, then we opened a parenthesis for @@ -1427,7 +1431,7 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) // token was empty (in which case we'll just confirm there is // more code in this file and not just a big comment). if ($this->tokens[$i]['line'] >= ($startLine + 30) - && isset(Util\Tokens::$emptyTokens[$this->tokens[($i - 1)]['code']]) === false + && isset(Tokens::$emptyTokens[$this->tokens[($i - 1)]['code']]) === false ) { if ($this->scopeOpeners[$currType]['strict'] === true) { if (PHP_CODESNIFFER_VERBOSITY > 1) { @@ -1516,14 +1520,14 @@ private function createLevelMap() $len = $this->tokens[$i]['length']; $col = $this->tokens[$i]['column']; - $content = Util\Common::prepareForOutput($this->tokens[$i]['content']); + $content = Common::prepareForOutput($this->tokens[$i]['content']); echo str_repeat("\t", ($level + 1)); echo "Process token $i on line $line [col:$col;len:$len;lvl:$level;"; if (empty($conditions) !== true) { $conditionString = 'conds;'; foreach ($conditions as $condition) { - $conditionString .= Util\Tokens::tokenName($condition).','; + $conditionString .= Tokens::tokenName($condition).','; } echo rtrim($conditionString, ',').';'; @@ -1584,14 +1588,14 @@ private function createLevelMap() $type = $this->tokens[$x]['type']; $oldConds = ''; foreach ($oldConditions as $condition) { - $oldConds .= Util\Tokens::tokenName($condition).','; + $oldConds .= Tokens::tokenName($condition).','; } $oldConds = rtrim($oldConds, ','); $newConds = ''; foreach ($this->tokens[$x]['conditions'] as $condition) { - $newConds .= Util\Tokens::tokenName($condition).','; + $newConds .= Tokens::tokenName($condition).','; } $newConds = rtrim($newConds, ','); @@ -1660,7 +1664,7 @@ private function createLevelMap() $oldCondition = array_pop($conditions); if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", ($level + 1)); - echo '* token '.Util\Tokens::tokenName($oldCondition).' removed from conditions array *'.PHP_EOL; + echo '* token '.Tokens::tokenName($oldCondition).' removed from conditions array *'.PHP_EOL; } // Make sure this closer actually belongs to us. @@ -1672,7 +1676,7 @@ private function createLevelMap() $badToken = $this->tokens[$oldOpener]['scope_condition']; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($oldCondition); + $type = Tokens::tokenName($oldCondition); echo str_repeat("\t", ($level + 1)); echo "* scope closer was bad, cleaning up $badToken:$type *".PHP_EOL; } @@ -1686,14 +1690,14 @@ private function createLevelMap() $type = $this->tokens[$x]['type']; $oldConds = ''; foreach ($oldConditions as $condition) { - $oldConds .= Util\Tokens::tokenName($condition).','; + $oldConds .= Tokens::tokenName($condition).','; } $oldConds = rtrim($oldConds, ','); $newConds = ''; foreach ($this->tokens[$x]['conditions'] as $condition) { - $newConds .= Util\Tokens::tokenName($condition).','; + $newConds .= Tokens::tokenName($condition).','; } $newConds = rtrim($newConds, ','); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php index 68abef59c..408de96e7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php @@ -4,14 +4,18 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; +use FilesystemIterator; use PHP_CodeSniffer\Autoload; use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; +use RecursiveCallbackFilterIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; class Cache { @@ -19,7 +23,7 @@ class Cache /** * The filesystem location of the cache file. * - * @var void + * @var string */ private static $path = ''; @@ -95,11 +99,11 @@ public static function load(Ruleset $ruleset, Config $config) // hash. This ensures that core PHPCS changes will also invalidate the cache. // Note that we ignore sniffs here, and any files that don't affect // the outcome of the run. - $di = new \RecursiveDirectoryIterator( + $di = new RecursiveDirectoryIterator( $installDir, - (\FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS) + (FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS) ); - $filter = new \RecursiveCallbackFilterIterator( + $filter = new RecursiveCallbackFilterIterator( $di, function ($file, $key, $iterator) { // Skip non-php files. @@ -126,7 +130,7 @@ function ($file, $key, $iterator) { } ); - $iterator = new \RecursiveIteratorIterator($filter); + $iterator = new RecursiveIteratorIterator($filter); foreach ($iterator as $file) { if (PHP_CODESNIFFER_VERBOSITY > 1) { echo "\t\t=> core file: $file".PHP_EOL; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php index ce7967cc3..cb6965f62 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php @@ -4,11 +4,14 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; +use InvalidArgumentException; +use Phar; + class Common { @@ -35,7 +38,7 @@ class Common * * @param string $path The path to use. * - * @return mixed + * @return bool */ public static function isPharFile($path) { @@ -83,7 +86,7 @@ public static function isReadable($path) * * @param string $path The path to use. * - * @return mixed + * @return string|false */ public static function realpath($path) { @@ -112,7 +115,7 @@ public static function realpath($path) return $path; } - $phar = \Phar::running(false); + $phar = Phar::running(false); $extra = str_replace('phar://'.$phar, '', $path); $path = realpath($phar); if ($path === false) { @@ -310,6 +313,20 @@ public static function prepareForOutput($content, $exclude=[]) }//end prepareForOutput() + /** + * Strip colors from a text for output to screen. + * + * @param string $text The text to process. + * + * @return string + */ + public static function stripColors($text) + { + return preg_replace('`\033\[[0-9;]+m`', '', $text); + + }//end stripColors() + + /** * Returns true if the specified string is in the camel caps format. * @@ -404,7 +421,7 @@ public static function isCamelCaps( */ public static function isUnderscoreName($string) { - // If there are space in the name, it can't be valid. + // If there is whitespace in the name, it can't be valid. if (strpos($string, ' ') !== false) { return false; } @@ -513,25 +530,43 @@ public static function suggestType($varType) * @param string $sniffClass The fully qualified sniff class name. * * @return string + * + * @throws \InvalidArgumentException When $sniffClass is not a non-empty string. + * @throws \InvalidArgumentException When $sniffClass is not a FQN for a sniff(test) class. */ public static function getSniffCode($sniffClass) { - $parts = explode('\\', $sniffClass); - $sniff = array_pop($parts); + if (is_string($sniffClass) === false || $sniffClass === '') { + throw new InvalidArgumentException('The $sniffClass parameter must be a non-empty string'); + } + + $parts = explode('\\', $sniffClass); + $partsCount = count($parts); + $sniff = $parts[($partsCount - 1)]; if (substr($sniff, -5) === 'Sniff') { // Sniff class name. $sniff = substr($sniff, 0, -5); - } else { + } else if (substr($sniff, -8) === 'UnitTest') { // Unit test class name. $sniff = substr($sniff, 0, -8); + } else { + throw new InvalidArgumentException( + 'The $sniffClass parameter was not passed a fully qualified sniff(test) class name. Received: '.$sniffClass + ); + } + + $standard = ''; + if (isset($parts[($partsCount - 4)]) === true) { + $standard = $parts[($partsCount - 4)]; + } + + $category = ''; + if (isset($parts[($partsCount - 2)]) === true) { + $category = $parts[($partsCount - 2)]; } - $category = array_pop($parts); - $sniffDir = array_pop($parts); - $standard = array_pop($parts); - $code = $standard.'.'.$category.'.'.$sniff; - return $code; + return $standard.'.'.$category.'.'.$sniff; }//end getSniffCode() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Help.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Help.php new file mode 100644 index 000000000..68d797678 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Help.php @@ -0,0 +1,625 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Util; + +use InvalidArgumentException; +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Util\Common; + +final class Help +{ + + + /** + * Short options which are available for both the `phpcs` as well as the `phpcbf` command. + * + * @var string + */ + const DEFAULT_SHORT_OPTIONS = '-hilnpqvw'; + + /** + * Long options which are available for both the `phpcs` as well as the `phpcbf` command. + * + * {@internal This should be a constant array, but those aren't supported until PHP 5.6.} + * + * @var string Comma-separated list of the option names. + */ + const DEFAULT_LONG_OPTIONS = 'basepath,bootstrap,colors,encoding,error-severity,exclude,extensions,file,file-list,filter,ignore,ignore-annotations,no-colors,parallel,php-ini,report-width,runtime-set,severity,sniffs,standard,stdin-path,tab-width,version,vv,vvv,warning-severity'; + + /** + * Minimum screen width. + * + * The help info needs room to display, so this is the minimum acceptable width. + * + * @var integer + */ + const MIN_WIDTH = 60; + + /** + * Indent option lines. + * + * @var string + */ + const INDENT = ' '; + + /** + * Gutter spacing for between the option argument info and the option description. + * + * @var string + */ + const GUTTER = ' '; + + /** + * The current PHPCS Configuration. + * + * @var \PHP_CodeSniffer\Config + */ + private $config; + + /** + * The options which should be shown for this help screen. + * + * @var array + */ + private $requestedOptions = []; + + /** + * Active options per category (after filtering). + * + * @var array>> + */ + private $activeOptions = []; + + /** + * Width of the indent for option lines. + * + * @var integer + */ + private $indentWidth = 0; + + /** + * Width of the gutter spacing. + * + * @var integer + */ + private $gutterWidth = 0; + + /** + * Width of longest option argument info entry. + * + * @var integer + */ + private $maxOptionNameLength = 0; + + + /** + * Constructor. + * + * @param \PHP_CodeSniffer\Config $config Configuration object. + * @param array $longOptions The long options which should be shown. + * @param string $shortOptions The short options which should be shown. + * + * @throws \InvalidArgumentException When $shortOptions is not a string. + */ + public function __construct(Config $config, array $longOptions, $shortOptions='') + { + if (is_string($shortOptions) === false) { + throw new InvalidArgumentException('The $shortOptions parameter must be a string'); + } + + $this->config = $config; + $this->requestedOptions = array_merge($longOptions, str_split($shortOptions)); + + $this->filterOptions(); + + $this->indentWidth = strlen(self::INDENT); + $this->gutterWidth = strlen(self::GUTTER); + + $this->setMaxOptionNameLength(); + + }//end __construct() + + + /** + * Display the help info. + * + * @return void + */ + public function display() + { + $this->printUsage(); + $this->printCategories(); + + }//end display() + + + /** + * Filter the available options based on the requested options. + * + * @return void + */ + private function filterOptions() + { + $filteredOptions = $this->getAllOptions(); + + foreach ($filteredOptions as $category => $options) { + // Initial state set to "true" to prevent a spacer at the start of an array. + $lastWasSpacer = true; + $spacerCount = 0; + + foreach ($options as $name => $option) { + if ($lastWasSpacer !== true && strpos($name, 'blank-line') === 0) { + ++$spacerCount; + $lastWasSpacer = true; + continue; + } + + if (in_array($name, $this->requestedOptions, true) === false) { + unset($filteredOptions[$category][$name]); + continue; + } + + $lastWasSpacer = false; + } + + // Make sure the final array doesn't contain a spacer at the end. + if (empty($filteredOptions[$category]) === false) { + end($filteredOptions[$category]); + $key = key($filteredOptions[$category]); + if (strpos($key, 'blank-line') === 0) { + unset($filteredOptions[$category][$key]); + --$spacerCount; + } + } + + // Remove categories now left empty. + if (empty($filteredOptions[$category]) === true || count($filteredOptions[$category]) === $spacerCount) { + unset($filteredOptions[$category]); + } + }//end foreach + + $this->activeOptions = $filteredOptions; + + }//end filterOptions() + + + /** + * Determine the length of the longest option argument and store it. + * + * @return void + */ + private function setMaxOptionNameLength() + { + $lengths = []; + foreach ($this->activeOptions as $category => $options) { + foreach ($options as $option) { + if (isset($option['argument']) === false) { + continue; + } + + $lengths[] = strlen($option['argument']); + } + } + + if (empty($lengths) === false) { + $this->maxOptionNameLength = max($lengths); + } + + }//end setMaxOptionNameLength() + + + /** + * Get the maximum width which can be used to display the help info. + * + * Independently of user preference/auto-determined width of the current screen, + * a minimum width is needed to display information, so don't allow this to get too low. + * + * @return int + */ + private function getMaxWidth() + { + return max(self::MIN_WIDTH, $this->config->reportWidth); + + }//end getMaxWidth() + + + /** + * Get the maximum width for the text in the option description column. + * + * @return int + */ + private function getDescriptionColumnWidth() + { + return ($this->getMaxWidth() - $this->maxOptionNameLength - $this->indentWidth - $this->gutterWidth); + + }//end getDescriptionColumnWidth() + + + /** + * Get the length of the indentation needed for follow up lines when the description does not fit on one line. + * + * @return int + */ + private function getDescriptionFollowupLineIndentLength() + { + return ($this->maxOptionNameLength + $this->indentWidth + $this->gutterWidth); + + }//end getDescriptionFollowupLineIndentLength() + + + /** + * Print basic usage information to the screen. + * + * @return void + */ + private function printUsage() + { + $command = 'phpcs'; + if (defined('PHP_CODESNIFFER_CBF') === true && PHP_CODESNIFFER_CBF === true) { + $command = 'phpcbf'; + } + + $this->printCategoryHeader('Usage'); + + echo self::INDENT.$command.' [options] '.PHP_EOL; + + }//end printUsage() + + + /** + * Print details of all the requested options to the screen, sorted by category. + * + * @return void + */ + private function printCategories() + { + foreach ($this->activeOptions as $category => $options) { + $this->printCategoryHeader($category); + $this->printCategoryOptions($options); + } + + }//end printCategories() + + + /** + * Print a category header. + * + * @param string $header The header text. + * + * @return void + */ + private function printCategoryHeader($header) + { + $header .= ':'; + if ($this->config->colors === true) { + $header = "\033[33m{$header}\033[0m"; + } + + echo PHP_EOL.$header.PHP_EOL; + + }//end printCategoryHeader() + + + /** + * Print the options for a category. + * + * @param array> $options The options to display. + * + * @return void + */ + private function printCategoryOptions(array $options) + { + $maxDescriptionWidth = $this->getDescriptionColumnWidth(); + $maxTextWidth = ($this->getMaxWidth() - $this->indentWidth); + $secondLineIndent = str_repeat(' ', $this->getDescriptionFollowupLineIndentLength()); + + $output = ''; + foreach ($options as $option) { + if (isset($option['spacer']) === true) { + $output .= PHP_EOL; + } + + if (isset($option['text']) === true) { + $text = wordwrap($option['text'], $maxTextWidth, "\n"); + $output .= self::INDENT.implode(PHP_EOL.self::INDENT, explode("\n", $text)).PHP_EOL; + } + + if (isset($option['argument'], $option['description']) === true) { + $argument = str_pad($option['argument'], $this->maxOptionNameLength); + $argument = $this->colorizeVariableInput($argument); + $output .= self::INDENT."\033[32m{$argument}\033[0m"; + $output .= self::GUTTER; + + $description = wordwrap($option['description'], $maxDescriptionWidth, "\n"); + $output .= implode(PHP_EOL.$secondLineIndent, explode("\n", $description)).PHP_EOL; + } + } + + if ($this->config->colors === false) { + $output = Common::stripColors($output); + } + + echo $output; + + }//end printCategoryOptions() + + + /** + * Colorize "variable" input in the option argument info. + * + * For the purposes of this method, "variable" input is text between <> brackets. + * The regex allows for multiple tags and nested tags. + * + * @param string $text The text to process. + * + * @return string + */ + private function colorizeVariableInput($text) + { + return preg_replace('`(<(?:(?>[^<>]+)|(?R))*>)`', "\033[36m".'$1'."\033[32m", $text); + + }//end colorizeVariableInput() + + + /** + * Retrieve the help details for all supported CLI arguments per category. + * + * @return array>> + */ + private function getAllOptions() + { + $options = []; + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Readability is more important. + $options['Scan targets'] = [ + 'file' => [ + 'argument' => '', + 'description' => 'One or more files and/or directories to check, space separated.', + ], + '-' => [ + 'argument' => '-', + 'description' => 'Check STDIN instead of local files and directories.', + ], + 'stdin-path' => [ + 'argument' => '--stdin-path=', + 'description' => 'If processing STDIN, the file path that STDIN will be processed as.', + ], + 'file-list' => [ + 'argument' => '--file-list=', + 'description' => 'Check the files and/or directories which are defined in the file to which the path is provided (one per line).', + ], + 'filter' => [ + 'argument' => '--filter=', + 'description' => 'Check based on a predefined file filter. Use either the "GitModified" or "GitStaged" filter, or specify the path to a custom filter class.', + ], + 'ignore' => [ + 'argument' => '--ignore=', + 'description' => 'Ignore files based on a comma-separated list of patterns matching files and/or directories.', + ], + 'extensions' => [ + 'argument' => '--extensions=', + 'description' => 'Check files with the specified file extensions (comma-separated list). Defaults to php,inc/php,js,css.'."\n" + .'The type of the file can be specified using: ext/type; e.g. module/php,es/js.', + ], + 'l' => [ + 'argument' => '-l', + 'description' => 'Check local directory only, no recursion.', + ], + ]; + + $options['Rule Selection Options'] = [ + 'standard' => [ + 'argument' => '--standard=', + 'description' => 'The name of, or the path to, the coding standard to use. Can be a comma-separated list specifying multiple standards. If no standard is specified, PHP_CodeSniffer will look for a [.]phpcs.xml[.dist] custom ruleset file in the current directory and those above it.', + ], + 'sniffs' => [ + 'argument' => '--sniffs=', + 'description' => 'A comma-separated list of sniff codes to limit the scan to. All sniffs must be part of the standard in use.', + ], + 'exclude' => [ + 'argument' => '--exclude=', + 'description' => 'A comma-separated list of sniff codes to exclude from the scan. All sniffs must be part of the standard in use.', + ], + 'blank-line' => ['spacer' => ''], + + 'i' => [ + 'argument' => '-i', + 'description' => 'Show a list of installed coding standards.', + ], + 'e' => [ + 'argument' => '-e', + 'description' => 'Explain a standard by showing the names of all the sniffs it includes.', + ], + 'generator' => [ + 'argument' => '--generator=', + 'description' => 'Show documentation for a standard. Use either the "HTML", "Markdown" or "Text" generator.', + ], + ]; + + $options['Run Options'] = [ + 'a' => [ + 'argument' => '-a', + 'description' => 'Run in interactive mode, pausing after each file.', + ], + 'bootstrap' => [ + 'argument' => '--bootstrap=', + 'description' => 'Run the specified file(s) before processing begins. A list of files can be provided, separated by commas.', + ], + 'cache' => [ + 'argument' => '--cache[=]', + 'description' => 'Cache results between runs. Optionally, can be provided to use a specific file for caching. Otherwise, a temporary file is used.', + ], + 'no-cache' => [ + 'argument' => '--no-cache', + 'description' => 'Do not cache results between runs (default).', + ], + 'parallel' => [ + 'argument' => '--parallel=', + 'description' => 'The number of files to be checked simultaneously. Defaults to 1 (no parallel processing).'."\n" + .'If enabled, this option only takes effect if the PHP PCNTL (Process Control) extension is available.', + ], + 'suffix' => [ + 'argument' => '--suffix=', + 'description' => 'Write modified files to a filename using this suffix ("diff" and "patch" are not used in this mode).', + ], + 'blank-line' => ['spacer' => ''], + + 'php-ini' => [ + 'argument' => '-d ', + 'description' => 'Set the [key] php.ini value to [value] or set to [true] if value is omitted.'."\n" + .'Note: only php.ini settings which can be changed at runtime are supported.', + ], + ]; + + $options['Reporting Options'] = [ + 'report' => [ + 'argument' => '--report=', + 'description' => 'Print either the "full", "xml", "checkstyle", "csv", "json", "junit", "emacs", "source", "summary", "diff", "svnblame", "gitblame", "hgblame", "notifysend" or "performance" report or specify the path to a custom report class. By default, the "full" report is displayed.', + ], + 'report-file' => [ + 'argument' => '--report-file=', + 'description' => 'Write the report to the specified file path.', + ], + 'report-report' => [ + 'argument' => '--report-=', + 'description' => 'Write the report specified in to the specified file path.', + ], + 'report-width' => [ + 'argument' => '--report-width=', + 'description' => 'How many columns wide screen reports should be. Set to "auto" to use current screen width, where supported.', + ], + 'basepath' => [ + 'argument' => '--basepath=', + 'description' => 'Strip a path from the front of file paths inside reports.', + ], + 'blank-line-1' => ['spacer' => ''], + + 'w' => [ + 'argument' => '-w', + 'description' => 'Include both warnings and errors (default).', + ], + 'n' => [ + 'argument' => '-n', + 'description' => 'Do not include warnings. Shortcut for "--warning-severity=0".', + ], + 'severity' => [ + 'argument' => '--severity=', + 'description' => 'The minimum severity required to display an error or warning. Defaults to 5.', + ], + 'error-severity' => [ + 'argument' => '--error-severity=', + 'description' => 'The minimum severity required to display an error. Defaults to 5.', + ], + 'warning-severity' => [ + 'argument' => '--warning-severity=', + 'description' => 'The minimum severity required to display a warning. Defaults to 5.', + ], + 'blank-line-2' => ['spacer' => ''], + + 's' => [ + 'argument' => '-s', + 'description' => 'Show sniff error codes in all reports.', + ], + 'ignore-annotations' => [ + 'argument' => '--ignore-annotations', + 'description' => 'Ignore all "phpcs:..." annotations in code comments.', + ], + 'colors' => [ + 'argument' => '--colors', + 'description' => 'Use colors in screen output.', + ], + 'no-colors' => [ + 'argument' => '--no-colors', + 'description' => 'Do not use colors in screen output (default).', + ], + 'p' => [ + 'argument' => '-p', + 'description' => 'Show progress of the run.', + ], + 'q' => [ + 'argument' => '-q', + 'description' => 'Quiet mode; disables progress and verbose output.', + ], + 'm' => [ + 'argument' => '-m', + 'description' => 'Stop error messages from being recorded. This saves a lot of memory but stops many reports from being used.', + ], + ]; + + $options['Configuration Options'] = [ + 'encoding' => [ + 'argument' => '--encoding=', + 'description' => 'The encoding of the files being checked. Defaults to "utf-8".', + ], + 'tab-width' => [ + 'argument' => '--tab-width=', + 'description' => 'The number of spaces each tab represents.', + ], + 'blank-line' => ['spacer' => ''], + + 'config-explain' => [ + 'text' => 'Default values for a selection of options can be stored in a user-specific CodeSniffer.conf configuration file.'."\n" + .'This applies to the following options: "default_standard", "report_format", "tab_width", "encoding", "severity", "error_severity", "warning_severity", "show_warnings", "report_width", "show_progress", "quiet", "colors", "cache", "parallel", "installed_paths", "php_version", "ignore_errors_on_exit", "ignore_warnings_on_exit".', + ], + 'config-show' => [ + 'argument' => '--config-show', + 'description' => 'Show the configuration options which are currently stored in the applicable CodeSniffer.conf file.', + ], + 'config-set' => [ + 'argument' => '--config-set ', + 'description' => 'Save a configuration option to the CodeSniffer.conf file.', + ], + 'config-delete' => [ + 'argument' => '--config-delete ', + 'description' => 'Delete a configuration option from the CodeSniffer.conf file.', + ], + 'runtime-set' => [ + 'argument' => '--runtime-set ', + 'description' => 'Set a configuration option to be applied to the current scan run only.', + ], + ]; + + $options['Miscellaneous Options'] = [ + 'h' => [ + 'argument' => '-h, -?, --help', + 'description' => 'Print this help message.', + ], + 'version' => [ + 'argument' => '--version', + 'description' => 'Print version information.', + ], + 'v' => [ + 'argument' => '-v', + 'description' => 'Verbose output: Print processed files.', + ], + 'vv' => [ + 'argument' => '-vv', + 'description' => 'Verbose output: Print ruleset and token output.', + ], + 'vvv' => [ + 'argument' => '-vvv', + 'description' => 'Verbose output: Print sniff processing information.', + ], + ]; + // phpcs:enable + + return $options; + + }//end getAllOptions() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/MessageCollector.php b/app/vendor/squizlabs/php_codesniffer/src/Util/MessageCollector.php new file mode 100644 index 000000000..6db9414c1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/MessageCollector.php @@ -0,0 +1,310 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Util; + +use InvalidArgumentException; +use PHP_CodeSniffer\Exceptions\RuntimeException; + +final class MessageCollector +{ + + /** + * Indicator for a (blocking) error. + * + * @var int + */ + const ERROR = 1; + + /** + * Indicator for a warning. + * + * @var int + */ + const WARNING = 2; + + /** + * Indicator for a notice. + * + * @var int + */ + const NOTICE = 4; + + /** + * Indicator for a deprecation notice. + * + * @var int + */ + const DEPRECATED = 8; + + /** + * Indicator for ordering the messages based on severity first, order received second. + * + * @var string + */ + const ORDERBY_SEVERITY = 'severity'; + + /** + * Indicator for ordering the messages based on the order in which they were received. + * + * @var string + */ + const ORDERBY_RECEIVED = 'received'; + + /** + * Collected messages. + * + * @var array> The value for each array entry is an associative array + * which holds two keys: + * - 'message' string The message text. + * - 'type' int The type of the message based on the + * above declared error level constants. + */ + private $cache = []; + + + /** + * Add a new message. + * + * @param string $message The message text. + * @param int $type The type of message. Should be one of the following constants: + * MessageCollector::ERROR, MessageCollector::WARNING, MessageCollector::NOTICE + * or MessageCollector::DEPRECATED. + * Defaults to MessageCollector::NOTICE. + * + * @return void + * + * @throws \InvalidArgumentException If the message text is not a string. + * @throws \InvalidArgumentException If the message type is not one of the accepted types. + */ + public function add($message, $type=self::NOTICE) + { + if (is_string($message) === false) { + throw new InvalidArgumentException('The $message should be of type string. Received: '.gettype($message).'.'); + } + + if ($type !== self::ERROR + && $type !== self::WARNING + && $type !== self::NOTICE + && $type !== self::DEPRECATED + ) { + throw new InvalidArgumentException('The message $type should be one of the predefined MessageCollector constants. Received: '.$type.'.'); + } + + $this->cache[] = [ + 'message' => $message, + 'type' => $type, + ]; + + }//end add() + + + /** + * Determine whether or not the currently cached errors include blocking errors. + * + * @return bool + */ + public function containsBlockingErrors() + { + $seenTypes = $this->arrayColumn($this->cache, 'type'); + $typeFrequency = array_count_values($seenTypes); + return isset($typeFrequency[self::ERROR]); + + }//end containsBlockingErrors() + + + /** + * Display the cached messages. + * + * Displaying the messages will also clear the message cache. + * + * @param string $order Optional. The order in which to display the messages. + * Should be one of the following constants: MessageCollector::ORDERBY_SEVERITY, + * MessageCollector::ORDERBY_RECEIVED. + * Defaults to MessageCollector::ORDERBY_SEVERITY. + * + * @return void + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException When there are blocking errors. + */ + public function display($order=self::ORDERBY_SEVERITY) + { + if ($this->cache === []) { + return; + } + + $blocking = $this->containsBlockingErrors(); + $messageInfo = $this->prefixAll($this->cache); + $this->clearCache(); + + if ($order === self::ORDERBY_RECEIVED) { + $messages = $this->arrayColumn($messageInfo, 'message'); + } else { + $messages = $this->sortBySeverity($messageInfo); + } + + $allMessages = implode(PHP_EOL, $messages).PHP_EOL.PHP_EOL; + + if ($blocking === true) { + throw new RuntimeException($allMessages); + } else { + echo $allMessages; + } + + }//end display() + + + /** + * Label all messages based on their type. + * + * @param array> $messages A multi-dimensional array of messages with their severity. + * + * @return array> + */ + private function prefixAll(array $messages) + { + foreach ($messages as $i => $details) { + $messages[$i]['message'] = $this->prefix($details['message'], $details['type']); + } + + return $messages; + + }//end prefixAll() + + + /** + * Add a message type prefix to a message. + * + * @param string $message The message text. + * @param int $type The type of message. + * + * @return string + */ + private function prefix($message, $type) + { + switch ($type) { + case self::ERROR: + $message = 'ERROR: '.$message; + break; + + case self::WARNING: + $message = 'WARNING: '.$message; + break; + + case self::DEPRECATED: + $message = 'DEPRECATED: '.$message; + break; + + default: + $message = 'NOTICE: '.$message; + break; + } + + return $message; + + }//end prefix() + + + /** + * Sort an array of messages by severity. + * + * @param array> $messages A multi-dimensional array of messages with their severity. + * + * @return array A single dimensional array of only messages, sorted by severity. + */ + private function sortBySeverity(array $messages) + { + if (count($messages) === 1) { + return [$messages[0]['message']]; + } + + $errors = []; + $warnings = []; + $notices = []; + $deprecations = []; + + foreach ($messages as $details) { + switch ($details['type']) { + case self::ERROR: + $errors[] = $details['message']; + break; + + case self::WARNING: + $warnings[] = $details['message']; + break; + + case self::DEPRECATED: + $deprecations[] = $details['message']; + break; + + default: + $notices[] = $details['message']; + break; + } + } + + return array_merge($errors, $warnings, $notices, $deprecations); + + }//end sortBySeverity() + + + /** + * Clear the message cache. + * + * @return void + */ + private function clearCache() + { + $this->cache = []; + + }//end clearCache() + + + /** + * Return the values from a single column in the input array. + * + * Polyfill for the PHP 5.5+ native array_column() function (for the functionality needed here). + * + * @param array> $input A multi-dimensional array from which to pull a column of values. + * @param string $columnKey The name of the column of values to return. + * + * @link https://www.php.net/function.array-column + * + * @return array + */ + private function arrayColumn(array $input, $columnKey) + { + if (function_exists('array_column') === true) { + // PHP 5.5+. + return array_column($input, $columnKey); + } + + // PHP 5.4. + $callback = function ($row) use ($columnKey) { + return $row[$columnKey]; + }; + + return array_map($callback, $input); + + }//end arrayColumn() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php index 65e5d6cb3..527f5b792 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php @@ -4,11 +4,12 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; +use DirectoryIterator; use PHP_CodeSniffer\Config; class Standards @@ -35,7 +36,7 @@ public static function getInstalledStandardPaths() $resolvedInstalledPaths = []; foreach ($installedPaths as $installedPath) { if (substr($installedPath, 0, 1) === '.') { - $installedPath = Common::realPath(__DIR__.$ds.'..'.$ds.'..'.$ds.$installedPath); + $installedPath = Common::realpath(__DIR__.$ds.'..'.$ds.'..'.$ds.$installedPath); if ($installedPath === false) { continue; } @@ -99,7 +100,7 @@ public static function getInstalledStandardDetails( continue; } - $di = new \DirectoryIterator($standardsDir); + $di = new DirectoryIterator($standardsDir); foreach ($di as $file) { if ($file->isDir() === true && $file->isDot() === false) { $filename = $file->getFilename(); @@ -190,7 +191,7 @@ public static function getInstalledStandards( continue; } - $di = new \DirectoryIterator($standardsDir); + $di = new DirectoryIterator($standardsDir); $standardsInDir = []; foreach ($di as $file) { if ($file->isDir() === true && $file->isDot() === false) { @@ -238,7 +239,7 @@ public static function isInstalledStandard($standard) } else { // This could be a custom standard, installed outside our // standards directory. - $standard = Common::realPath($standard); + $standard = Common::realpath($standard); if ($standard === false) { return false; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php index 95ee85216..95f6810b3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; @@ -13,7 +13,21 @@ class Timing { /** - * The start time of the run. + * Number of milliseconds in a minute. + * + * @var int + */ + const MINUTE_IN_MS = 60000; + + /** + * Number of milliseconds in a second. + * + * @var int + */ + const SECOND_IN_MS = 1000; + + /** + * The start time of the run in microseconds. * * @var float */ @@ -40,6 +54,51 @@ public static function startTiming() }//end startTiming() + /** + * Get the duration of the run up to "now". + * + * @return float Duration in milliseconds. + */ + public static function getDuration() + { + if (self::$startTime === null) { + // Timing was never started. + return 0; + } + + return ((microtime(true) - self::$startTime) * 1000); + + }//end getDuration() + + + /** + * Convert a duration in milliseconds to a human readable duration string. + * + * @param float $duration Duration in milliseconds. + * + * @return string + */ + public static function getHumanReadableDuration($duration) + { + $timeString = ''; + if ($duration >= self::MINUTE_IN_MS) { + $mins = floor($duration / self::MINUTE_IN_MS); + $secs = round((fmod($duration, self::MINUTE_IN_MS) / self::SECOND_IN_MS), 2); + $timeString = $mins.' mins'; + if ($secs >= 0.01) { + $timeString .= ", $secs secs"; + } + } else if ($duration >= self::SECOND_IN_MS) { + $timeString = round(($duration / self::SECOND_IN_MS), 2).' secs'; + } else { + $timeString = round($duration).'ms'; + } + + return $timeString; + + }//end getHumanReadableDuration() + + /** * Print information about the run. * @@ -60,23 +119,11 @@ public static function printRunTime($force=false) return; } - $time = ((microtime(true) - self::$startTime) * 1000); - - if ($time > 60000) { - $mins = floor($time / 60000); - $secs = round((fmod($time, 60000) / 1000), 2); - $time = $mins.' mins'; - if ($secs !== 0) { - $time .= ", $secs secs"; - } - } else if ($time > 1000) { - $time = round(($time / 1000), 2).' secs'; - } else { - $time = round($time).'ms'; - } + $duration = self::getDuration(); + $duration = self::getHumanReadableDuration($duration); $mem = round((memory_get_peak_usage(true) / (1024 * 1024)), 2).'MB'; - echo "Time: $time; Memory: $mem".PHP_EOL.PHP_EOL; + echo "Time: $duration; Memory: $mem".PHP_EOL.PHP_EOL; self::$printed = true; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php index bb1fb2ca9..73cf02ddd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; @@ -82,6 +82,13 @@ define('T_ATTRIBUTE_END', 'PHPCS_T_ATTRIBUTE_END'); define('T_ENUM_CASE', 'PHPCS_T_ENUM_CASE'); define('T_TYPE_INTERSECTION', 'PHPCS_T_TYPE_INTERSECTION'); +define('T_TYPE_OPEN_PARENTHESIS', 'PHPCS_T_TYPE_OPEN_PARENTHESIS'); +define('T_TYPE_CLOSE_PARENTHESIS', 'PHPCS_T_TYPE_CLOSE_PARENTHESIS'); + +/* + * {@internal IMPORTANT: all PHP native polyfilled tokens MUST be added to the + * `PHP_CodeSniffer\Tests\Core\Util\Tokens\TokenNameTest::dataPolyfilledPHPNativeTokens()` test method!} + */ // Some PHP 5.5 tokens, replicated for lower versions. if (defined('T_FINALLY') === false) { @@ -775,12 +782,14 @@ public static function tokenName($token) * For example T_CLASS tokens appear very infrequently in a file, and * therefore have a high weighting. * - * Returns false if there are no weightings for any of the specified tokens. + * If there are no weightings for any of the specified tokens, the first token + * seen in the passed array will be returned. * * @param array $tokens The token types to get the highest weighted * type for. * - * @return int|false The highest weighted token. + * @return int The highest weighted token. + * On equal "weight", returns the first token of that particular weight. */ public static function getHighestWeightedToken(array $tokens) { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php b/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php index 9d099c1e3..4fa41d9d9 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php @@ -4,19 +4,13 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; -if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === false) { - include_once 'Core/AllTests.php'; - include_once 'Standards/AllSniffs.php'; -} else { - include_once 'CodeSniffer/Core/AllTests.php'; - include_once 'CodeSniffer/Standards/AllSniffs.php'; - include_once 'FileList.php'; -} +require_once 'Core/AllTests.php'; +require_once 'Standards/AllSniffs.php'; // PHPUnit 7 made the TestSuite run() method incompatible with // older PHPUnit versions due to return type hints, so maintain @@ -24,7 +18,7 @@ $phpunit7 = false; if (class_exists('\PHPUnit\Runner\Version') === true) { $version = \PHPUnit\Runner\Version::id(); - if ($version[0] === '7') { + if (version_compare($version, '7.0', '>=') === true) { $phpunit7 = true; } } diff --git a/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php b/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php new file mode 100644 index 000000000..8ebce0585 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php @@ -0,0 +1,212 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests; + +use PHP_CodeSniffer\Config; +use ReflectionProperty; + +final class ConfigDouble extends Config +{ + + /** + * Whether or not the setting of a standard should be skipped. + * + * @var boolean + */ + private $skipSettingStandard = false; + + + /** + * Creates a clean Config object and populates it with command line values. + * + * @param array $cliArgs An array of values gathered from CLI args. + * @param bool $skipSettingStandard Whether to skip setting a standard to prevent + * the Config class trying to auto-discover a ruleset file. + * Should only be set to `true` for tests which actually test + * the ruleset auto-discovery. + * Note: there is no need to set this to `true` when a standard + * is being passed via the `$cliArgs`. Those settings will always + * be respected. + * Defaults to `false`. Will result in the standard being set + * to "PSR1" if not provided via `$cliArgs`. + * @param bool $skipSettingReportWidth Whether to skip setting a report-width to prevent + * the Config class trying to auto-discover the screen width. + * Should only be set to `true` for tests which actually test + * the screen width auto-discovery. + * Note: there is no need to set this to `true` when a report-width + * is being passed via the `$cliArgs`. Those settings will always + * respected. + * Defaults to `false`. Will result in the reportWidth being set + * to "80" if not provided via `$cliArgs`. + * + * @return void + */ + public function __construct(array $cliArgs=[], $skipSettingStandard=false, $skipSettingReportWidth=false) + { + $this->skipSettingStandard = $skipSettingStandard; + + $this->resetSelectProperties(); + $this->preventReadingCodeSnifferConfFile(); + + parent::__construct($cliArgs); + + if ($skipSettingReportWidth !== true) { + $this->preventAutoDiscoveryScreenWidth(); + } + + }//end __construct() + + + /** + * Ensures the static properties in the Config class are reset to their default values + * when the ConfigDouble is no longer used. + * + * @return void + */ + public function __destruct() + { + $this->setStaticConfigProperty('overriddenDefaults', []); + $this->setStaticConfigProperty('executablePaths', []); + $this->setStaticConfigProperty('configData', null); + $this->setStaticConfigProperty('configDataFile', null); + + }//end __destruct() + + + /** + * Sets the command line values and optionally prevents a file system search for a custom ruleset. + * + * @param array $args An array of command line arguments to set. + * + * @return void + */ + public function setCommandLineValues($args) + { + parent::setCommandLineValues($args); + + if ($this->skipSettingStandard !== true) { + $this->preventSearchingForRuleset(); + } + + }//end setCommandLineValues() + + + /** + * Reset a few properties on the Config class to their default values. + * + * @return void + */ + private function resetSelectProperties() + { + $this->setStaticConfigProperty('overriddenDefaults', []); + $this->setStaticConfigProperty('executablePaths', []); + + }//end resetSelectProperties() + + + /** + * Prevent the values in a potentially available user-specific `CodeSniffer.conf` file + * from influencing the tests. + * + * This also prevents some file system calls which can influence the test runtime. + * + * @return void + */ + private function preventReadingCodeSnifferConfFile() + { + $this->setStaticConfigProperty('configData', []); + $this->setStaticConfigProperty('configDataFile', ''); + + }//end preventReadingCodeSnifferConfFile() + + + /** + * Prevent searching for a custom ruleset by setting a standard, but only if the test + * being run doesn't set a standard itself. + * + * This also prevents some file system calls which can influence the test runtime. + * + * The standard being set is the smallest one available so the ruleset initialization + * will be the fastest possible. + * + * @return void + */ + private function preventSearchingForRuleset() + { + $overriddenDefaults = $this->getStaticConfigProperty('overriddenDefaults'); + if (isset($overriddenDefaults['standards']) === false) { + $this->standards = ['PSR1']; + $overriddenDefaults['standards'] = true; + } + + self::setStaticConfigProperty('overriddenDefaults', $overriddenDefaults); + + }//end preventSearchingForRuleset() + + + /** + * Prevent a call to stty to figure out the screen width, but only if the test being run + * doesn't set a report width itself. + * + * @return void + */ + private function preventAutoDiscoveryScreenWidth() + { + $settings = $this->getSettings(); + if ($settings['reportWidth'] === 'auto') { + $this->reportWidth = self::DEFAULT_REPORT_WIDTH; + } + + }//end preventAutoDiscoveryScreenWidth() + + + /** + * Helper function to retrieve the value of a private static property on the Config class. + * + * @param string $name The name of the property to retrieve. + * + * @return mixed + */ + private function getStaticConfigProperty($name) + { + $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); + $property->setAccessible(true); + return $property->getValue(); + + }//end getStaticConfigProperty() + + + /** + * Helper function to set the value of a private static property on the Config class. + * + * @param string $name The name of the property to set. + * @param mixed $value The value to set the property to. + * + * @return void + */ + private function setStaticConfigProperty($name, $value) + { + $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); + $property->setAccessible(true); + $property->setValue(null, $value); + $property->setAccessible(false); + + }//end setStaticConfigProperty() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php index 4d4f54699..3418be498 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php @@ -4,14 +4,16 @@ * * @author Juliette Reinders Folmer * @copyright 2018-2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core; -use PHP_CodeSniffer\Config; -use PHP_CodeSniffer\Ruleset; +use Exception; use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; abstract class AbstractMethodUnitTest extends TestCase @@ -27,6 +29,15 @@ abstract class AbstractMethodUnitTest extends TestCase */ protected static $fileExtension = 'inc'; + /** + * The tab width setting to use when tokenizing the file. + * + * This allows for test case files to use a different tab width than the default. + * + * @var integer + */ + protected static $tabWidth = 4; + /** * The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file. * @@ -41,12 +52,16 @@ abstract class AbstractMethodUnitTest extends TestCase * The test case file for a unit test class has to be in the same directory * directory and use the same file name as the test class, using the .inc extension. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function initializeFile() { - $config = new Config(); - $config->standards = ['PSR1']; + $_SERVER['argv'] = []; + $config = new ConfigDouble(); + // Also set a tab-width to enable testing tab-replaced vs `orig_content`. + $config->tabWidth = static::$tabWidth; $ruleset = new Ruleset($config); @@ -60,21 +75,87 @@ public static function setUpBeforeClass() $contents .= file_get_contents($pathToTestFile); self::$phpcsFile = new DummyFile($contents, $ruleset, $config); - self::$phpcsFile->process(); + self::$phpcsFile->parse(); + + }//end initializeFile() + + + /** + * Clean up after finished test by resetting all static properties on the class to their default values. + * + * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()} + * method. + * + * @afterClass + * + * @return void + */ + public static function reset() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when `self::$phpcsFile` is reset, but we can't definitively rely on that). + if (isset(self::$phpcsFile) === true) { + self::$phpcsFile->config->__destruct(); + } + + self::$fileExtension = 'inc'; + self::$tabWidth = 4; + self::$phpcsFile = null; - }//end setUpBeforeClass() + }//end reset() /** - * Clean up after finished test. + * Test QA: verify that a test case file does not contain any duplicate test markers. + * + * When a test case file contains a lot of test cases, it is easy to overlook that a test marker name + * is already in use. + * A test wouldn't necessarily fail on this, but would not be testing what is intended to be tested as + * it would be verifying token properties for the wrong token. + * + * This test safeguards against this. + * + * @coversNothing * * @return void */ - public static function tearDownAfterClass() + public function testTestMarkersAreUnique() { - self::$phpcsFile = null; + $this->assertTestMarkersAreUnique(self::$phpcsFile); - }//end tearDownAfterClass() + }//end testTestMarkersAreUnique() + + + /** + * Assertion to verify that a test case file does not contain any duplicate test markers. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file to validate. + * + * @return void + */ + public static function assertTestMarkersAreUnique(File $phpcsFile) + { + $tokens = $phpcsFile->getTokens(); + + // Collect all marker comments in the file. + $seenComments = []; + for ($i = 0; $i < $phpcsFile->numTokens; $i++) { + if ($tokens[$i]['code'] !== T_COMMENT) { + continue; + } + + if (stripos($tokens[$i]['content'], '/* test') !== 0) { + continue; + } + + $seenComments[] = $tokens[$i]['content']; + } + + self::assertSame(array_unique($seenComments), $seenComments, 'Duplicate test markers found.'); + + }//end assertTestMarkersAreUnique() /** @@ -83,16 +164,39 @@ public static function tearDownAfterClass() * Note: the test delimiter comment MUST start with "/* test" to allow this function to * distinguish between comments used *in* a test and test delimiters. * - * @param string $commentString The delimiter comment to look for. - * @param int|string|array $tokenType The type of token(s) to look for. - * @param string $tokenContent Optional. The token content for the target token. + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. * * @return int */ public function getTargetToken($commentString, $tokenType, $tokenContent=null) { - $start = (self::$phpcsFile->numTokens - 1); - $comment = self::$phpcsFile->findPrevious( + return self::getTargetTokenFromFile(self::$phpcsFile, $commentString, $tokenType, $tokenContent); + + }//end getTargetToken() + + + /** + * Get the token pointer for a target token based on a specific comment found on the line before. + * + * Note: the test delimiter comment MUST start with "/* test" to allow this function to + * distinguish between comments used *in* a test and test delimiters. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file to find the token in. + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. + * + * @return int + * + * @throws Exception When the test delimiter comment is not found. + * @throws Exception When the test target token is not found. + */ + public static function getTargetTokenFromFile(File $phpcsFile, $commentString, $tokenType, $tokenContent=null) + { + $start = ($phpcsFile->numTokens - 1); + $comment = $phpcsFile->findPrevious( T_COMMENT, $start, null, @@ -100,7 +204,13 @@ public function getTargetToken($commentString, $tokenType, $tokenContent=null) $commentString ); - $tokens = self::$phpcsFile->getTokens(); + if ($comment === false) { + throw new Exception( + sprintf('Failed to find the test marker: %s in test case file %s', $commentString, $phpcsFile->getFilename()) + ); + } + + $tokens = $phpcsFile->getTokens(); $end = ($start + 1); // Limit the token finding to between this and the next delimiter comment. @@ -115,7 +225,7 @@ public function getTargetToken($commentString, $tokenType, $tokenContent=null) } } - $target = self::$phpcsFile->findNext( + $target = $phpcsFile->findNext( $tokenType, ($comment + 1), $end, @@ -126,15 +236,39 @@ public function getTargetToken($commentString, $tokenType, $tokenContent=null) if ($target === false) { $msg = 'Failed to find test target token for comment string: '.$commentString; if ($tokenContent !== null) { - $msg .= ' With token content: '.$tokenContent; + $msg .= ' with token content: '.$tokenContent; } - $this->assertFalse(true, $msg); + throw new Exception($msg); } return $target; - }//end getTargetToken() + }//end getTargetTokenFromFile() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException in a PHPUnit cross-version + * compatible manner. + * + * @param string $message The expected exception message. + * + * @return void + */ + public function expectRunTimeException($message) + { + $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + }//end expectRunTimeException() }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php index 304690eff..a5465f987 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php @@ -5,14 +5,14 @@ * @author Greg Sherwood * @author Juliette Reinders Folmer * @copyright 2006-2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core; use PHP_CodeSniffer\Tests\FileList; -use PHPUnit\TextUI\TestRunner; use PHPUnit\Framework\TestSuite; +use PHPUnit\TextUI\TestRunner; class AllTests { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php index c0f38fa6f..e719c7eb7 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Autoloader; @@ -12,20 +12,27 @@ use PHP_CodeSniffer\Autoload; use PHPUnit\Framework\TestCase; -class DetermineLoadedClassTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Autoload::determineLoadedClass method. + * + * @covers \PHP_CodeSniffer\Autoload::determineLoadedClass + */ +final class DetermineLoadedClassTest extends TestCase { /** * Load the test files. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function includeFixture() { include __DIR__.'/TestFiles/Sub/C.inc'; - }//end setUpBeforeClass() + }//end includeFixture() /** @@ -53,7 +60,7 @@ public function testOrdered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); }//end testOrdered() @@ -83,7 +90,7 @@ public function testUnordered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); $classesAfterLoad = [ 'classes' => [ @@ -97,7 +104,7 @@ public function testUnordered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); $classesAfterLoad = [ 'classes' => [ @@ -111,7 +118,7 @@ public function testUnordered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); }//end testUnordered() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php new file mode 100644 index 000000000..6f5cd8844 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php @@ -0,0 +1,92 @@ +setAccessible(true); + $property->setValue(null, $value); + $property->setAccessible(false); + + }//end setStaticConfigProperty() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php new file mode 100644 index 000000000..e63b1fef9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php @@ -0,0 +1,128 @@ +assertSame($expected, $config->extensions); + + }//end testValidExtensions() + + + /** + * Data provider. + * + * @see self::testValidExtensions() + * + * @return array>> + */ + public static function dataValidExtensions() + { + return [ + // Passing an empty extensions list is not useful, as it will result in no files being scanned, + // but that's the responsibility of the user. + 'Empty extensions list' => [ + 'passedValue' => '', + 'expected' => [], + ], + 'Single extension passed: php' => [ + 'passedValue' => 'php', + 'expected' => [ + 'php' => 'PHP', + ], + ], + // This would cause PHPCS to scan python files as PHP, which will probably cause very weird scan results, + // but that's the responsibility of the user. + 'Single extension passed: py' => [ + 'passedValue' => 'py', + 'expected' => [ + 'py' => 'PHP', + ], + ], + // This would likely result in a problem when PHPCS can't find a "PY" tokenizer class, + // but that's not our concern at this moment. Support for non-PHP tokenizers is being dropped soon anyway. + 'Single extension passed with language: py/py' => [ + 'passedValue' => 'py/py', + 'expected' => [ + 'py' => 'PY', + ], + ], + 'Multiple extensions passed: php,js,css' => [ + 'passedValue' => 'php,js,css', + 'expected' => [ + 'php' => 'PHP', + 'js' => 'JS', + 'css' => 'CSS', + ], + ], + 'Multiple extensions passed, some with language: php,inc/php,phpt/php,js' => [ + 'passedValue' => 'php,inc/php,phpt/php,js', + 'expected' => [ + 'php' => 'PHP', + 'inc' => 'PHP', + 'phpt' => 'PHP', + 'js' => 'JS', + ], + ], + 'File extensions are set case sensitively (and filtering is case sensitive too)' => [ + 'passedValue' => 'PHP,php', + 'expected' => [ + 'PHP' => 'PHP', + 'php' => 'PHP', + ], + ], + ]; + + }//end dataValidExtensions() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @return void + */ + public function testOnlySetOnce() + { + $config = new ConfigDouble( + [ + '--extensions=php', + '--extensions=inc,module', + ] + ); + + $this->assertSame(['php' => 'PHP'], $config->extensions); + + }//end testOnlySetOnce() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php new file mode 100644 index 000000000..5def5f68f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php @@ -0,0 +1,147 @@ +assertSame($expectedPropertyValue, $config->generator); + + }//end testValidGenerators() + + + /** + * Data provider for testValidGenerators(). + * + * @see self::testValidGenerators() + * + * @return array> + */ + public static function dataValidGeneratorNames() + { + return [ + 'Text generator passed' => [ + 'argumentValue' => 'Text', + 'expectedPropertyValue' => 'Text', + ], + 'HTML generator passed' => [ + 'argumentValue' => 'HTML', + 'expectedPropertyValue' => 'HTML', + ], + 'Markdown generator passed' => [ + 'argumentValue' => 'Markdown', + 'expectedPropertyValue' => 'Markdown', + ], + 'Uppercase Text generator passed' => [ + 'argumentValue' => 'TEXT', + 'expectedPropertyValue' => 'Text', + ], + 'Mixed case Text generator passed' => [ + 'argumentValue' => 'tEXt', + 'expectedPropertyValue' => 'Text', + ], + 'Lowercase HTML generator passed' => [ + 'argumentValue' => 'html', + 'expectedPropertyValue' => 'HTML', + ], + ]; + + }//end dataValidGeneratorNames() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @return void + */ + public function testOnlySetOnce() + { + $config = new ConfigDouble( + [ + '--generator=Text', + '--generator=HTML', + '--generator=InvalidGenerator', + ] + ); + + $this->assertSame('Text', $config->generator); + + }//end testOnlySetOnce() + + + /** + * Ensure that an exception is thrown for an invalid generator. + * + * @param string $generatorName Generator name. + * + * @dataProvider dataInvalidGeneratorNames + * + * @return void + */ + public function testInvalidGenerator($generatorName) + { + $exception = 'PHP_CodeSniffer\Exceptions\DeepExitException'; + $message = 'ERROR: "'.$generatorName.'" is not a valid generator. The following generators are supported: Text, HTML and Markdown.'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new ConfigDouble(["--generator={$generatorName}"]); + + }//end testInvalidGenerator() + + + /** + * Data provider for testInvalidGenerator(). + * + * @see self::testInvalidGenerator() + * + * @return array> + */ + public static function dataInvalidGeneratorNames() + { + return [ + ['InvalidGenerator'], + ['Text,HTML'], + [''], + ]; + + }//end dataInvalidGeneratorNames() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php new file mode 100644 index 000000000..28b996228 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php @@ -0,0 +1,260 @@ + + * @copyright 2006-2023 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Config; + +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Tests\Core\Config\AbstractRealConfigTestCase; + +/** + * Tests for the \PHP_CodeSniffer\Config reportWidth value. + * + * @covers \PHP_CodeSniffer\Config::__get + */ +final class ReportWidthTest extends AbstractRealConfigTestCase +{ + + + /** + * Test that report width without overrules will always be set to a non-0 positive integer. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::restoreDefaults + * + * @return void + */ + public function testReportWidthDefault() + { + $config = new Config(['--standard=PSR1']); + + // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. + $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); + $this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0'); + + }//end testReportWidthDefault() + + + /** + * Test that the report width will be set to a non-0 positive integer when not found in the CodeSniffer.conf file. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::restoreDefaults + * + * @return void + */ + public function testReportWidthWillBeSetFromAutoWhenNotFoundInConfFile() + { + $phpCodeSnifferConfig = [ + 'default_standard' => 'PSR2', + 'show_warnings' => '0', + ]; + + $this->setStaticConfigProperty('configData', $phpCodeSnifferConfig); + + $config = new Config(['--standard=PSR1']); + + // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. + $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); + $this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0'); + + }//end testReportWidthWillBeSetFromAutoWhenNotFoundInConfFile() + + + /** + * Test that the report width will be set correctly when found in the CodeSniffer.conf file. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::getConfigData + * @covers \PHP_CodeSniffer\Config::restoreDefaults + * + * @return void + */ + public function testReportWidthCanBeSetFromConfFile() + { + $phpCodeSnifferConfig = [ + 'default_standard' => 'PSR2', + 'report_width' => '120', + ]; + + $this->setStaticConfigProperty('configData', $phpCodeSnifferConfig); + + $config = new Config(['--standard=PSR1']); + $this->assertSame(120, $config->reportWidth); + + }//end testReportWidthCanBeSetFromConfFile() + + + /** + * Test that the report width will be set correctly when passed as a CLI argument. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::processLongArgument + * + * @return void + */ + public function testReportWidthCanBeSetFromCLI() + { + $_SERVER['argv'] = [ + 'phpcs', + '--standard=PSR1', + '--report-width=100', + ]; + + $config = new Config(); + $this->assertSame(100, $config->reportWidth); + + }//end testReportWidthCanBeSetFromCLI() + + + /** + * Test that the report width will be set correctly when multiple report widths are passed on the CLI. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::processLongArgument + * + * @return void + */ + public function testReportWidthWhenSetFromCLIFirstValuePrevails() + { + $_SERVER['argv'] = [ + 'phpcs', + '--standard=PSR1', + '--report-width=100', + '--report-width=200', + ]; + + $config = new Config(); + $this->assertSame(100, $config->reportWidth); + + }//end testReportWidthWhenSetFromCLIFirstValuePrevails() + + + /** + * Test that a report width passed as a CLI argument will overrule a report width set in a CodeSniffer.conf file. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::processLongArgument + * @covers \PHP_CodeSniffer\Config::getConfigData + * + * @return void + */ + public function testReportWidthSetFromCLIOverrulesConfFile() + { + $phpCodeSnifferConfig = [ + 'default_standard' => 'PSR2', + 'report_format' => 'summary', + 'show_warnings' => '0', + 'show_progress' => '1', + 'report_width' => '120', + ]; + + $this->setStaticConfigProperty('configData', $phpCodeSnifferConfig); + + $cliArgs = [ + 'phpcs', + '--standard=PSR1', + '--report-width=180', + ]; + + $config = new Config($cliArgs); + $this->assertSame(180, $config->reportWidth); + + }//end testReportWidthSetFromCLIOverrulesConfFile() + + + /** + * Test that the report width will be set to a non-0 positive integer when set to "auto". + * + * @covers \PHP_CodeSniffer\Config::__set + * + * @return void + */ + public function testReportWidthInputHandlingForAuto() + { + $config = new Config(['--standard=PSR1']); + $config->reportWidth = 'auto'; + + // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. + $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); + $this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0'); + + }//end testReportWidthInputHandlingForAuto() + + + /** + * Test that the report width will be set correctly for various types of input. + * + * @param mixed $value Input value received. + * @param int $expected Expected report width. + * + * @dataProvider dataReportWidthInputHandling + * @covers \PHP_CodeSniffer\Config::__set + * + * @return void + */ + public function testReportWidthInputHandling($value, $expected) + { + $config = new Config(['--standard=PSR1']); + $config->reportWidth = $value; + + $this->assertSame($expected, $config->reportWidth); + + }//end testReportWidthInputHandling() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataReportWidthInputHandling() + { + return [ + 'No value (empty string)' => [ + 'value' => '', + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid input type null' => [ + 'value' => null, + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid input type false' => [ + 'value' => false, + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid input type float' => [ + 'value' => 100.50, + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid string value "invalid"' => [ + 'value' => 'invalid', + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid string value, non-integer string "50.25"' => [ + 'value' => '50.25', + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: valid numeric string value' => [ + 'value' => '250', + 'expected' => 250, + ], + 'Value: valid int value' => [ + 'value' => 220, + 'expected' => 220, + ], + 'Value: negative int value becomes positive int' => [ + 'value' => -180, + 'expected' => 180, + ], + ]; + + }//end dataReportWidthInputHandling() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/SniffsExcludeArgsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/SniffsExcludeArgsTest.php new file mode 100644 index 000000000..59aabecc1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/SniffsExcludeArgsTest.php @@ -0,0 +1,322 @@ + + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Config; + +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Config --sniffs and --exclude arguments. + * + * @covers \PHP_CodeSniffer\Config::parseSniffCodes + * @covers \PHP_CodeSniffer\Config::processLongArgument + */ +final class SniffsExcludeArgsTest extends TestCase +{ + + + /** + * Ensure that the expected error message is returned for invalid arguments. + * + * @param string $argument 'sniffs' or 'exclude'. + * @param string $value List of sniffs to include / exclude. + * @param array $errors Sniff code and associated help text. + * @param string|null $suggestion Help text shown to end user with correct syntax for argument. + * + * @return void + * @dataProvider dataInvalid + */ + public function testInvalid($argument, $value, $errors, $suggestion) + { + $exception = 'PHP_CodeSniffer\Exceptions\DeepExitException'; + $message = 'ERROR: The --'.$argument.' option only supports sniff codes.'.PHP_EOL; + $message .= 'Sniff codes are in the form "Standard.Category.Sniff".'.PHP_EOL; + $message .= PHP_EOL; + $message .= 'The following problems were detected:'.PHP_EOL; + $message .= '* '.implode(PHP_EOL.'* ', $errors).PHP_EOL; + + if ($suggestion !== null) { + $message .= PHP_EOL; + $message .= "Perhaps try --$argument=\"$suggestion\" instead.".PHP_EOL; + } + + $message .= PHP_EOL; + $message .= 'Run "phpcs --help" for usage information'.PHP_EOL; + $message .= PHP_EOL; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new ConfigDouble(["--$argument=$value"]); + + }//end testInvalid() + + + /** + * Data provider for testInvalid(). + * + * @see self::testInvalid() + * @return array|string|null>> + */ + public static function dataInvalid() + { + $arguments = [ + 'sniffs', + 'exclude', + ]; + $data = []; + + foreach ($arguments as $argument) { + // Empty values are errors. + $data[$argument.'; empty string'] = [ + 'argument' => $argument, + 'value' => '', + 'errors' => [ + 'No codes specified / empty argument', + ], + 'suggestion' => null, + ]; + $data[$argument.'; one comma alone'] = [ + 'argument' => $argument, + 'value' => ',', + 'errors' => [ + 'No codes specified / empty argument', + ], + 'suggestion' => null, + ]; + $data[$argument.'; two commas alone'] = [ + 'argument' => $argument, + 'value' => ',,', + 'errors' => [ + 'No codes specified / empty argument', + ], + 'suggestion' => null, + ]; + + // A standard is not a valid sniff. + $data[$argument.'; standard'] = [ + 'argument' => $argument, + 'value' => 'Standard', + 'errors' => [ + 'Standard codes are not supported: Standard', + ], + 'suggestion' => null, + ]; + + // A category is not a valid sniff. + $data[$argument.'; category'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category', + 'errors' => [ + 'Category codes are not supported: Standard.Category', + ], + 'suggestion' => null, + ]; + + // An error-code is not a valid sniff. + $data[$argument.'; error-code'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff.Code', + 'errors' => [ + 'Message codes are not supported: Standard.Category.Sniff.Code', + ], + 'suggestion' => 'Standard.Category.Sniff', + ]; + + // Too many dots. + $data[$argument.'; too many dots'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff.Code.Extra', + 'errors' => [ + 'Too many parts: Standard.Category.Sniff.Code.Extra', + ], + 'suggestion' => 'Standard.Category.Sniff', + ]; + + // All errors are reported in one go. + $data[$argument.'; two errors'] = [ + 'argument' => $argument, + 'value' => 'StandardOne,StandardTwo', + 'errors' => [ + 'Standard codes are not supported: StandardOne', + 'Standard codes are not supported: StandardTwo', + ], + 'suggestion' => null, + ]; + + // Order of valid/invalid does not impact error reporting. + $data[$argument.'; valid followed by invalid'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category.Sniff,StandardTwo.Category', + 'errors' => [ + 'Category codes are not supported: StandardTwo.Category', + ], + 'suggestion' => 'StandardOne.Category.Sniff', + ]; + $data[$argument.'; invalid followed by valid'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category,StandardTwo.Category.Sniff', + 'errors' => [ + 'Category codes are not supported: StandardOne.Category', + ], + 'suggestion' => 'StandardTwo.Category.Sniff', + ]; + + // Different cases are reported individually (in duplicate), but suggestions are reduced. + $data[$argument.'; case mismatch - different errors'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff.Code,sTANDARD.cATEGORY.sNIFF.cODE.eXTRA', + 'errors' => [ + 'Message codes are not supported: Standard.Category.Sniff.Code', + 'Too many parts: sTANDARD.cATEGORY.sNIFF.cODE.eXTRA', + ], + 'suggestion' => 'Standard.Category.Sniff', + ]; + $data[$argument.'; case mismatch - same error'] = [ + 'argument' => $argument, + 'value' => 'sTANDARD.cATEGORY.sNIFF.cODE,Standard.Category.Sniff.Code', + 'errors' => [ + 'Message codes are not supported: sTANDARD.cATEGORY.sNIFF.cODE', + 'Message codes are not supported: Standard.Category.Sniff.Code', + ], + 'suggestion' => 'sTANDARD.cATEGORY.sNIFF', + ]; + }//end foreach + + return $data; + + }//end dataInvalid() + + + /** + * Ensure that the valid data does not throw an exception, and the value is stored. + * + * @param string $argument 'sniffs' or 'exclude'. + * @param string $value List of sniffs to include or exclude. + * @param array $result Expected sniffs to be set on the Config object. + * + * @return void + * @dataProvider dataValid + */ + public function testValid($argument, $value, $result) + { + $config = new ConfigDouble(["--$argument=$value"]); + + $this->assertSame($result, $config->$argument); + + }//end testValid() + + + /** + * Data provider for testValid(). + * + * @see self::testValid() + * @return array|string>> + */ + public static function dataValid() + { + $arguments = [ + 'sniffs', + 'exclude', + ]; + $data = []; + + foreach ($arguments as $argument) { + $data[$argument.'; one valid sniff'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff', + 'result' => ['Standard.Category.Sniff'], + ]; + $data[$argument.'; two valid sniffs'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category.Sniff,StandardTwo.Category.Sniff', + 'result' => [ + 'StandardOne.Category.Sniff', + 'StandardTwo.Category.Sniff', + ], + ]; + + // Rogue commas are quietly ignored. + $data[$argument.'; trailing comma'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff,', + 'result' => ['Standard.Category.Sniff'], + ]; + $data[$argument.'; double comma between sniffs'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category.Sniff,,StandardTwo.Category.Sniff', + 'result' => [ + 'StandardOne.Category.Sniff', + 'StandardTwo.Category.Sniff', + ], + ]; + + // Duplicates are reduced silently. + $data[$argument.'; one valid sniff twice'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff,Standard.Category.Sniff', + 'result' => ['Standard.Category.Sniff'], + ]; + $data[$argument.'; one valid sniff in different cases'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff, standard.category.sniff, STANDARD.CATEGORY.SNIFF', + 'result' => ['Standard.Category.Sniff'], + ]; + }//end foreach + + return $data; + + }//end dataValid() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @param string $argument 'sniffs' or 'exclude'. + * + * @return void + * @dataProvider dataOnlySetOnce + */ + public function testOnlySetOnce($argument) + { + $config = new ConfigDouble( + [ + "--$argument=StandardOne.Category.Sniff", + "--$argument=StandardTwo.Category.Sniff", + "--$argument=Standard.AnotherCategory.Sniff", + ] + ); + + $this->assertSame(['StandardOne.Category.Sniff'], $config->$argument); + + }//end testOnlySetOnce() + + + /** + * Data provider for testOnlySetOnce(). + * + * @return array> + */ + public static function dataOnlySetOnce() + { + return [ + 'sniffs' => ['sniffs'], + 'exclude' => ['exclude'], + ]; + + }//end dataOnlySetOnce() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php index 7181613c6..ebf851230 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php @@ -4,17 +4,23 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core; -use PHP_CodeSniffer\Config; -use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; -class ErrorSuppressionTest extends TestCase +/** + * Tests for PHP_CodeSniffer error suppression tags. + * + * @covers PHP_CodeSniffer\Files\File::addMessage + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class ErrorSuppressionTest extends TestCase { @@ -27,7 +33,6 @@ class ErrorSuppressionTest extends TestCase * Defaults to 0. * * @dataProvider dataSuppressError - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -36,7 +41,7 @@ public function testSuppressError($before, $after, $expectedErrors=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -58,9 +63,9 @@ public function testSuppressError($before, $after, $expectedErrors=0) * * @see testSuppressError() * - * @return array + * @return array> */ - public function dataSuppressError() + public static function dataSuppressError() { return [ 'no suppression' => [ @@ -160,7 +165,6 @@ public function dataSuppressError() * Defaults to 1. * * @dataProvider dataSuppressSomeErrors - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -169,7 +173,7 @@ public function testSuppressSomeErrors($before, $between, $expectedErrors=1) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -197,9 +201,9 @@ public function testSuppressSomeErrors($before, $between, $expectedErrors=1) * * @see testSuppressSomeErrors() * - * @return array + * @return array> */ - public function dataSuppressSomeErrors() + public static function dataSuppressSomeErrors() { return [ 'no suppression' => [ @@ -253,7 +257,6 @@ public function dataSuppressSomeErrors() * Defaults to 0. * * @dataProvider dataSuppressWarning - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -262,7 +265,7 @@ public function testSuppressWarning($before, $after, $expectedWarnings=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.Commenting.Todo']; @@ -289,9 +292,9 @@ public function testSuppressWarning($before, $after, $expectedWarnings=0) * * @see testSuppressWarning() * - * @return array + * @return array> */ - public function dataSuppressWarning() + public static function dataSuppressWarning() { return [ 'no suppression' => [ @@ -338,7 +341,6 @@ public function dataSuppressWarning() * Defaults to 1. * * @dataProvider dataSuppressLine - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -347,7 +349,7 @@ public function testSuppressLine($before, $after='', $expectedErrors=1) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -374,9 +376,9 @@ public function testSuppressLine($before, $after='', $expectedErrors=1) * * @see testSuppressLine() * - * @return array + * @return array> */ - public function dataSuppressLine() + public static function dataSuppressLine() { return [ 'no suppression' => [ @@ -386,12 +388,24 @@ public function dataSuppressLine() ], // With suppression on line before. - 'ignore: line before, slash comment' => ['before' => '// phpcs:ignore'], - 'ignore: line before, slash comment, with @' => ['before' => '// @phpcs:ignore'], - 'ignore: line before, hash comment' => ['before' => '# phpcs:ignore'], - 'ignore: line before, hash comment, with @' => ['before' => '# @phpcs:ignore'], - 'ignore: line before, star comment' => ['before' => '/* phpcs:ignore */'], - 'ignore: line before, star comment, with @' => ['before' => '/* @phpcs:ignore */'], + 'ignore: line before, slash comment' => [ + 'before' => '// phpcs:ignore', + ], + 'ignore: line before, slash comment, with @' => [ + 'before' => '// @phpcs:ignore', + ], + 'ignore: line before, hash comment' => [ + 'before' => '# phpcs:ignore', + ], + 'ignore: line before, hash comment, with @' => [ + 'before' => '# @phpcs:ignore', + ], + 'ignore: line before, star comment' => [ + 'before' => '/* phpcs:ignore */', + ], + 'ignore: line before, star comment, with @' => [ + 'before' => '/* @phpcs:ignore */', + ], // With suppression as trailing comment on code line. 'ignore: end of line, slash comment' => [ @@ -412,7 +426,9 @@ public function dataSuppressLine() ], // Deprecated syntax. - 'old style: line before, slash comment' => ['before' => '// @codingStandardsIgnoreLine'], + 'old style: line before, slash comment' => [ + 'before' => '// @codingStandardsIgnoreLine', + ], 'old style: end of line, slash comment' => [ 'before' => '', 'after' => ' // @codingStandardsIgnoreLine', @@ -425,13 +441,11 @@ public function dataSuppressLine() /** * Test suppressing a single error using a single line ignore in the middle of a line. * - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap - * * @return void */ public function testSuppressLineMidLine() { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -450,13 +464,11 @@ public function testSuppressLineMidLine() /** * Test suppressing a single error using a single line ignore within a docblock. * - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap - * * @return void */ public function testSuppressLineWithinDocblock() { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.Files.LineLength']; @@ -488,7 +500,6 @@ public function testSuppressLineWithinDocblock() * @param string $after Annotation to place after the code. * * @dataProvider dataNestedSuppressLine - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -497,7 +508,7 @@ public function testNestedSuppressLine($before, $after) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -525,9 +536,9 @@ public function testNestedSuppressLine($before, $after) * * @see testNestedSuppressLine() * - * @return array + * @return array> */ - public function dataNestedSuppressLine() + public static function dataNestedSuppressLine() { return [ // Process with disable/enable suppression and no single line suppression. @@ -579,7 +590,6 @@ public function dataNestedSuppressLine() * Defaults to 0. * * @dataProvider dataSuppressScope - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -588,14 +598,13 @@ public function testSuppressScope($before, $after, $expectedErrors=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['PEAR']; $config->sniffs = ['PEAR.Functions.FunctionDeclaration']; $ruleset = new Ruleset($config); } - $content = '> */ - public function dataSuppressScope() + public static function dataSuppressScope() { return [ 'no suppression' => [ @@ -677,7 +686,6 @@ public function dataSuppressScope() * Defaults to 0. * * @dataProvider dataSuppressFile - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -686,7 +694,7 @@ public function testSuppressFile($before, $after='', $expectedWarnings=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.Commenting.Todo']; @@ -715,28 +723,42 @@ class MyClass {} * * @see testSuppressFile() * - * @return array + * @return array> */ - public function dataSuppressFile() + public static function dataSuppressFile() { return [ 'no suppression' => [ - 'before' => '', - 'after' => '', - 'expectedErrors' => 1, + 'before' => '', + 'after' => '', + 'expectedWarnings' => 1, ], // Process with suppression. - 'ignoreFile: start of file, slash comment' => ['before' => '// phpcs:ignoreFile'], - 'ignoreFile: start of file, slash comment, with @' => ['before' => '// @phpcs:ignoreFile'], - 'ignoreFile: start of file, slash comment, mixed case' => ['before' => '// PHPCS:Ignorefile'], - 'ignoreFile: start of file, hash comment' => ['before' => '# phpcs:ignoreFile'], - 'ignoreFile: start of file, hash comment, with @' => ['before' => '# @phpcs:ignoreFile'], - 'ignoreFile: start of file, single-line star comment' => ['before' => '/* phpcs:ignoreFile */'], + 'ignoreFile: start of file, slash comment' => [ + 'before' => '// phpcs:ignoreFile', + ], + 'ignoreFile: start of file, slash comment, with @' => [ + 'before' => '// @phpcs:ignoreFile', + ], + 'ignoreFile: start of file, slash comment, mixed case' => [ + 'before' => '// PHPCS:Ignorefile', + ], + 'ignoreFile: start of file, hash comment' => [ + 'before' => '# phpcs:ignoreFile', + ], + 'ignoreFile: start of file, hash comment, with @' => [ + 'before' => '# @phpcs:ignoreFile', + ], + 'ignoreFile: start of file, single-line star comment' => [ + 'before' => '/* phpcs:ignoreFile */', + ], 'ignoreFile: start of file, multi-line star comment' => [ 'before' => '/*'.PHP_EOL.' phpcs:ignoreFile'.PHP_EOL.' */', ], - 'ignoreFile: start of file, single-line docblock comment' => ['before' => '/** phpcs:ignoreFile */'], + 'ignoreFile: start of file, single-line docblock comment' => [ + 'before' => '/** phpcs:ignoreFile */', + ], // Process late comment. 'ignoreFile: late comment, slash comment' => [ @@ -745,12 +767,18 @@ public function dataSuppressFile() ], // Deprecated syntax. - 'old style: start of file, slash comment' => ['before' => '// @codingStandardsIgnoreFile'], - 'old style: start of file, single-line star comment' => ['before' => '/* @codingStandardsIgnoreFile */'], + 'old style: start of file, slash comment' => [ + 'before' => '// @codingStandardsIgnoreFile', + ], + 'old style: start of file, single-line star comment' => [ + 'before' => '/* @codingStandardsIgnoreFile */', + ], 'old style: start of file, multi-line star comment' => [ 'before' => '/*'.PHP_EOL.' @codingStandardsIgnoreFile'.PHP_EOL.' */', ], - 'old style: start of file, single-line docblock comment' => ['before' => '/** @codingStandardsIgnoreFile */'], + 'old style: start of file, single-line docblock comment' => [ + 'before' => '/** @codingStandardsIgnoreFile */', + ], // Deprecated syntax, late comment. 'old style: late comment, slash comment' => [ @@ -772,7 +800,6 @@ public function dataSuppressFile() * Defaults to 0. * * @dataProvider dataDisableSelected - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -781,7 +808,7 @@ public function testDisableSelected($before, $expectedErrors=0, $expectedWarning static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -814,9 +841,9 @@ public function testDisableSelected($before, $expectedErrors=0, $expectedWarning * * @see testDisableSelected() * - * @return array + * @return array> */ - public function dataDisableSelected() + public static function dataDisableSelected() { return [ // Single sniff. @@ -838,7 +865,9 @@ public function dataDisableSelected() ], // Multiple sniffs. - 'disable: multiple sniffs in one comment' => ['before' => '// phpcs:disable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant'], + 'disable: multiple sniffs in one comment' => [ + 'before' => '// phpcs:disable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant', + ], 'disable: multiple sniff in multiple comments' => [ 'before' => '// phpcs:disable Generic.Commenting.Todo'.PHP_EOL.'// phpcs:disable Generic.PHP.LowerCaseConstant', ], @@ -848,12 +877,16 @@ public function dataDisableSelected() 'before' => '// phpcs:disable Generic.Commenting', 'expectedErrors' => 1, ], - 'disable: whole standard' => ['before' => '// phpcs:disable Generic'], + 'disable: whole standard' => [ + 'before' => '// phpcs:disable Generic', + ], 'disable: single errorcode' => [ 'before' => '# @phpcs:disable Generic.Commenting.Todo.TaskFound', 'expectedErrors' => 1, ], - 'disable: single errorcode and a category' => ['before' => '// phpcs:disable Generic.PHP.LowerCaseConstant.Found,Generic.Commenting'], + 'disable: single errorcode and a category' => [ + 'before' => '// phpcs:disable Generic.PHP.LowerCaseConstant.Found,Generic.Commenting', + ], // Wrong category/sniff/code. 'disable: wrong error code and category' => [ @@ -884,7 +917,6 @@ public function dataDisableSelected() * @param int $expectedWarnings Number of warnings expected. * * @dataProvider dataEnableSelected - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -893,7 +925,7 @@ public function testEnableSelected($code, $expectedErrors, $expectedWarnings) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -921,9 +953,9 @@ public function testEnableSelected($code, $expectedErrors, $expectedWarnings) * * @see testEnableSelected() * - * @return array + * @return array> */ - public function dataEnableSelected() + public static function dataEnableSelected() { return [ 'disable/enable: a single sniff' => [ @@ -1059,7 +1091,6 @@ public function dataEnableSelected() * @param int $expectedWarnings Number of warnings expected. * * @dataProvider dataIgnoreSelected - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -1068,7 +1099,7 @@ public function testIgnoreSelected($before, $expectedErrors, $expectedWarnings) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -1101,9 +1132,9 @@ public function testIgnoreSelected($before, $expectedErrors, $expectedWarnings) * * @see testIgnoreSelected() * - * @return array + * @return array> */ - public function dataIgnoreSelected() + public static function dataIgnoreSelected() { return [ 'no suppression' => [ @@ -1151,7 +1182,6 @@ public function dataIgnoreSelected() * @param int $expectedWarnings Number of warnings expected. * * @dataProvider dataCommenting - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -1160,7 +1190,7 @@ public function testCommenting($code, $expectedErrors, $expectedWarnings) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -1188,9 +1218,9 @@ public function testCommenting($code, $expectedErrors, $expectedWarnings) * * @see testCommenting() * - * @return array + * @return array> */ - public function dataCommenting() + public static function dataCommenting() { return [ 'ignore: single sniff' => [ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php index 7bff26b56..be8f458ae 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php @@ -1,20 +1,62 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; -class FindEndOfStatementTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::findEndOfStatement method. + * + * @covers \PHP_CodeSniffer\Files\File::findEndOfStatement + */ +final class FindEndOfStatementTest extends AbstractMethodUnitTest { + /** + * Test that end of statement is NEVER before the "current" token. + * + * @return void + */ + public function testEndIsNeverLessThanCurrentToken() + { + $tokens = self::$phpcsFile->getTokens(); + $errors = []; + + for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + $end = self::$phpcsFile->findEndOfStatement($i); + + // Collect all the errors. + if ($end < $i) { + $errors[] = sprintf( + 'End of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is less than %1$d', + $i, + $tokens[$i]['type'], + $tokens[$i]['content'], + $tokens[$i]['line'], + $end, + $tokens[$end]['type'] + ); + } + } + + $this->assertSame([], $errors); + + }//end testEndIsNeverLessThanCurrentToken() + + /** * Test a simple assignment. * diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc index aead06cd9..dae2cd969 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc @@ -1,27 +1,32 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class FindExtendedClassNameTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::findExtendedClassName method. + * + * @covers \PHP_CodeSniffer\Files\File::findExtendedClassName + */ +final class FindExtendedClassNameTest extends AbstractMethodUnitTest { + /** + * Test getting a `false` result when a non-existent token is passed. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->findExtendedClassName(100000); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test getting a `false` result when a token other than one of the supported tokens is passed. + * + * @return void + */ + public function testNotAClass() + { + $token = $this->getTargetToken('/* testNotAClass */', [T_FUNCTION]); + $result = self::$phpcsFile->findExtendedClassName($token); + $this->assertFalse($result); + + }//end testNotAClass() + + /** * Test retrieving the name of the class being extended by another class * (or interface). * - * @param string $identifier Comment which precedes the test case. - * @param bool $expected Expected function output. + * @param string $identifier Comment which precedes the test case. + * @param string|false $expected Expected function output. * * @dataProvider dataExtendedClass * @@ -40,50 +72,70 @@ public function testFindExtendedClassName($identifier, $expected) * * @see testFindExtendedClassName() * - * @return array + * @return array> */ - public function dataExtendedClass() + public static function dataExtendedClass() { return [ - [ - '/* testExtendedClass */', - 'testFECNClass', + 'class does not extend' => [ + 'identifier' => '/* testNonExtendedClass */', + 'expected' => false, + ], + 'class extends unqualified class' => [ + 'identifier' => '/* testExtendsUnqualifiedClass */', + 'expected' => 'testFECNClass', + ], + 'class extends fully qualified class' => [ + 'identifier' => '/* testExtendsFullyQualifiedClass */', + 'expected' => '\PHP_CodeSniffer\Tests\Core\File\testFECNClass', + ], + 'class extends partially qualified class' => [ + 'identifier' => '/* testExtendsPartiallyQualifiedClass */', + 'expected' => 'Core\File\RelativeClass', + ], + 'interface does not extend' => [ + 'identifier' => '/* testNonExtendedInterface */', + 'expected' => false, + ], + 'interface extends unqualified interface' => [ + 'identifier' => '/* testInterfaceExtendsUnqualifiedInterface */', + 'expected' => 'testFECNInterface', ], - [ - '/* testNamespacedClass */', - '\PHP_CodeSniffer\Tests\Core\File\testFECNClass', + 'interface extends fully qualified interface' => [ + 'identifier' => '/* testInterfaceExtendsFullyQualifiedInterface */', + 'expected' => '\PHP_CodeSniffer\Tests\Core\File\testFECNInterface', ], - [ - '/* testNonExtendedClass */', - false, + 'anon class extends unqualified class' => [ + 'identifier' => '/* testExtendedAnonClass */', + 'expected' => 'testFECNExtendedAnonClass', ], - [ - '/* testInterface */', - false, + 'class does not extend but contains anon class which extends' => [ + 'identifier' => '/* testNestedExtendedClass */', + 'expected' => false, ], - [ - '/* testInterfaceThatExtendsInterface */', - 'testFECNInterface', + 'anon class extends, nested in non-extended class' => [ + 'identifier' => '/* testNestedExtendedAnonClass */', + 'expected' => 'testFECNAnonClass', ], - [ - '/* testInterfaceThatExtendsFQCNInterface */', - '\PHP_CodeSniffer\Tests\Core\File\testFECNInterface', + 'class extends and implements' => [ + 'identifier' => '/* testClassThatExtendsAndImplements */', + 'expected' => 'testFECNClass', ], - [ - '/* testNestedExtendedClass */', - false, + 'class implements and extends' => [ + 'identifier' => '/* testClassThatImplementsAndExtends */', + 'expected' => 'testFECNClass', ], - [ - '/* testNestedExtendedAnonClass */', - 'testFECNAnonClass', + 'interface extends multiple interfaces (not supported)' => [ + 'identifier' => '/* testInterfaceMultiExtends */', + 'expected' => '\Package\FooInterface', ], - [ - '/* testClassThatExtendsAndImplements */', - 'testFECNClass', + 'parse error - extends keyword, but no class name' => [ + 'identifier' => '/* testMissingExtendsName */', + 'expected' => false, ], - [ - '/* testClassThatImplementsAndExtends */', - 'testFECNClass', + 'parse error - live coding - no curly braces' => [ + 'identifier' => '/* testParseError */', + 'expected' => false, ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc index 44c0f6432..3246efa2c 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc @@ -1,23 +1,25 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class FindImplementedInterfaceNamesTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames method. + * + * @covers \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames + */ +final class FindImplementedInterfaceNamesTest extends AbstractMethodUnitTest { + /** + * Test getting a `false` result when a non-existent token is passed. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->findImplementedInterfaceNames(100000); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test getting a `false` result when a token other than one of the supported tokens is passed. + * + * @return void + */ + public function testNotAClass() + { + $token = $this->getTargetToken('/* testNotAClass */', [T_FUNCTION]); + $result = self::$phpcsFile->findImplementedInterfaceNames($token); + $this->assertFalse($result); + + }//end testNotAClass() + + /** * Test retrieving the name(s) of the interfaces being implemented by a class. * - * @param string $identifier Comment which precedes the test case. - * @param bool $expected Expected function output. + * @param string $identifier Comment which precedes the test case. + * @param array|false $expected Expected function output. * * @dataProvider dataImplementedInterface * @@ -39,63 +71,89 @@ public function testFindImplementedInterfaceNames($identifier, $expected) * * @see testFindImplementedInterfaceNames() * - * @return array + * @return array|false>> */ - public function dataImplementedInterface() + public static function dataImplementedInterface() { return [ - [ - '/* testImplementedClass */', - ['testFIINInterface'], + 'interface declaration, no implements' => [ + 'identifier' => '/* testPlainInterface */', + 'expected' => false, ], - [ - '/* testMultiImplementedClass */', - [ + 'class does not implement' => [ + 'identifier' => '/* testNonImplementedClass */', + 'expected' => false, + ], + 'class implements single interface, unqualified' => [ + 'identifier' => '/* testClassImplementsSingle */', + 'expected' => [ 'testFIINInterface', - 'testFIINInterface2', ], ], - [ - '/* testNamespacedClass */', - ['\PHP_CodeSniffer\Tests\Core\File\testFIINInterface'], + 'class implements multiple interfaces' => [ + 'identifier' => '/* testClassImplementsMultiple */', + 'expected' => [ + 'testFIINInterface', + 'testFIINInterface2', + ], ], - [ - '/* testNonImplementedClass */', - false, + 'class implements single interface, fully qualified' => [ + 'identifier' => '/* testImplementsFullyQualified */', + 'expected' => [ + '\PHP_CodeSniffer\Tests\Core\File\testFIINInterface', + ], ], - [ - '/* testInterface */', - false, + 'class implements single interface, partially qualified' => [ + 'identifier' => '/* testImplementsPartiallyQualified */', + 'expected' => [ + 'Core\File\RelativeInterface', + ], ], - [ - '/* testClassThatExtendsAndImplements */', - [ + 'class extends and implements' => [ + 'identifier' => '/* testClassThatExtendsAndImplements */', + 'expected' => [ 'InterfaceA', '\NameSpaced\Cat\InterfaceB', ], ], - [ - '/* testClassThatImplementsAndExtends */', - [ + 'class implements and extends' => [ + 'identifier' => '/* testClassThatImplementsAndExtends */', + 'expected' => [ '\InterfaceA', 'InterfaceB', ], ], - [ - '/* testBackedEnumWithoutImplements */', - false, + 'enum does not implement' => [ + 'identifier' => '/* testBackedEnumWithoutImplements */', + 'expected' => false, ], - [ - '/* testEnumImplements */', - ['Colorful'], + 'enum implements single interface, unqualified' => [ + 'identifier' => '/* testEnumImplementsSingle */', + 'expected' => [ + 'Colorful', + ], ], - [ - '/* testBackedEnumImplements */', - [ + 'enum implements multiple interfaces, unqualified + fully qualified' => [ + 'identifier' => '/* testBackedEnumImplementsMulti */', + 'expected' => [ 'Colorful', '\Deck', ], ], + 'anon class implements single interface, unqualified' => [ + 'identifier' => '/* testAnonClassImplementsSingle */', + 'expected' => [ + 'testFIINInterface', + ], + ], + 'parse error - implements keyword, but no interface name' => [ + 'identifier' => '/* testMissingImplementsName */', + 'expected' => false, + ], + 'parse error - live coding - no curly braces' => [ + 'identifier' => '/* testParseError */', + 'expected' => false, + ], ]; }//end dataImplementedInterface() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc index ce9dfad3f..5b601075a 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc @@ -14,7 +14,7 @@ while(true) {} $a = 1; /* testClosureAssignment */ -$a = function($b=false;){}; +$a = function($b=false){}; /* testHeredocFunctionArg */ myFunction(<< fn() => return 1, - 'b' => fn() => return 1, + 'a' => fn() => 1, + 'b' => fn() => 1, ]; /* testStaticArrowFunction */ @@ -121,3 +121,88 @@ return 0; ?>

Test

', foo(), ''; + +$value = [ + /* testPrecededByArrowFunctionInArray - Expected */ + Url::make('View Song', fn($song) => $song->url()) + /* testPrecededByArrowFunctionInArray */ + ->onlyOnDetail(), + + new Panel('Information', [ + Text::make('Title') + ]), +]; + +switch ($foo) { + /* testCaseStatement */ + case 1: + /* testInsideCaseStatement */ + $var = doSomething(); + /* testInsideCaseBreakStatement */ + break 1; + + case 2: + /* testInsideCaseContinueStatement */ + continue 1; + + case 3: + /* testInsideCaseReturnStatement */ + return false; + + case 4: + /* testInsideCaseExitStatement */ + exit(1); + + case 5: + /* testInsideCaseThrowStatement */ + throw new Exception(); + + case 6: + $var = doSomething(); + /* testInsideCaseGotoStatement */ + goto myLabel; + + /* testDefaultStatement */ + default: + /* testInsideDefaultContinueStatement */ + continue $var; +} + +myLabel: +do_something(); + +match ($var) { + true => + /* test437ClosureDeclaration */ + function ($var) { + /* test437EchoNestedWithinClosureWithinMatch */ + echo $var, 'text', PHP_EOL; + }, + default => false +}; + +match ($var) { + /* test437NestedLongArrayWithinMatch */ + 'a' => array( 1, 2.5, $var), + /* test437NestedFunctionCallWithinMatch */ + 'b' => functionCall( 11, $var, 50.50), + /* test437NestedArrowFunctionWithinMatch */ + 'c' => fn($p1, /* test437FnSecondParamWithinMatch */ $p2) => $p1 + $p2, + default => false +}; + +callMe($paramA, match ($var) { + /* test437NestedLongArrayWithinNestedMatch */ + 'a' => array( 1, 2.5, $var), + /* test437NestedFunctionCallWithinNestedMatch */ + 'b' => functionCall( 11, $var, 50.50), + /* test437NestedArrowFunctionWithinNestedMatch */ + 'c' => fn($p1, /* test437FnSecondParamWithinNestedMatch */ $p2) => $p1 + $p2, + default => false +}); + +match ($var) { + /* test437NestedShortArrayWithinMatch */ + 'a' => [ 1, 2.5, $var], + default => false +}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php index ff859eca1..aa0646c6d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php @@ -3,18 +3,62 @@ * Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method. * * @author Greg Sherwood + * @author Juliette Reinders Folmer * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; -class FindStartOfStatementTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method. + * + * @covers \PHP_CodeSniffer\Files\File::findStartOfStatement + */ +final class FindStartOfStatementTest extends AbstractMethodUnitTest { + /** + * Test that start of statement is NEVER beyond the "current" token. + * + * @return void + */ + public function testStartIsNeverMoreThanCurrentToken() + { + $tokens = self::$phpcsFile->getTokens(); + $errors = []; + + for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + $start = self::$phpcsFile->findStartOfStatement($i); + + // Collect all the errors. + if ($start > $i) { + $errors[] = sprintf( + 'Start of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is more than %1$d', + $i, + $tokens[$i]['type'], + $tokens[$i]['content'], + $tokens[$i]['line'], + $start, + $tokens[$start]['type'] + ); + } + } + + $this->assertSame([], $errors); + + }//end testStartIsNeverMoreThanCurrentToken() + + /** * Test a simple assignment. * @@ -85,7 +129,7 @@ public function testClosureAssignment() $start = $this->getTargetToken('/* testClosureAssignment */', T_CLOSE_CURLY_BRACKET); $found = self::$phpcsFile->findStartOfStatement($start); - $this->assertSame(($start - 12), $found); + $this->assertSame(($start - 11), $found); }//end testClosureAssignment() @@ -217,7 +261,7 @@ public function testArrowFunctionArrayValue() $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_COMMA); $found = self::$phpcsFile->findStartOfStatement($start); - $this->assertSame(($start - 9), $found); + $this->assertSame(($start - 7), $found); }//end testArrowFunctionArrayValue() @@ -500,4 +544,440 @@ public function testOpenTagWithEcho() }//end testOpenTagWithEcho() + /** + * Test object call on result of static function call with arrow function as parameter and wrapped within an array. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2849 + * @link https://github.com/squizlabs/PHP_CodeSniffer/commit/fbf67efc3fc0c2a355f5585d49f4f6fe160ff2f9 + * + * @return void + */ + public function testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray() + { + $expected = $this->getTargetToken('/* testPrecededByArrowFunctionInArray - Expected */', T_STRING, 'Url'); + + $start = $this->getTargetToken('/* testPrecededByArrowFunctionInArray */', T_STRING, 'onlyOnDetail'); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame($expected, $found); + + }//end testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray() + + + /** + * Test finding the start of a statement inside a switch control structure case/default statement. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targets The token to search for after the test marker. + * @param string|int $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/squizlabs/php_codesniffer/issues/3192 + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3186/commits/18a0e54735bb9b3850fec266e5f4c50dacf618ea + * + * @dataProvider dataFindStartInsideSwitchCaseDefaultStatements + * + * @return void + */ + public function testFindStartInsideSwitchCaseDefaultStatements($testMarker, $targets, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $targets); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideSwitchCaseDefaultStatements() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideSwitchCaseDefaultStatements() + { + return [ + 'Case keyword should be start of case statement - case itself' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => T_CASE, + 'expectedTarget' => T_CASE, + ], + 'Case keyword should be start of case statement - number (what\'s being compared)' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_CASE, + ], + 'Variable should be start of arbitrary assignment statement - variable itself' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - equal sign' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_EQUAL, + 'expectedTarget' => T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - function call' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_VARIABLE, + ], + 'Break should be start for contents of the break statement - contents' => [ + 'testMarker' => '/* testInsideCaseBreakStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_BREAK, + ], + 'Continue should be start for contents of the continue statement - contents' => [ + 'testMarker' => '/* testInsideCaseContinueStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_CONTINUE, + ], + 'Return should be start for contents of the return statement - contents' => [ + 'testMarker' => '/* testInsideCaseReturnStatement */', + 'targets' => T_FALSE, + 'expectedTarget' => T_RETURN, + ], + 'Exit should be start for contents of the exit statement - close parenthesis' => [ + // Note: not sure if this is actually correct - should this be the open parenthesis ? + 'testMarker' => '/* testInsideCaseExitStatement */', + 'targets' => T_CLOSE_PARENTHESIS, + 'expectedTarget' => T_EXIT, + ], + 'Throw should be start for contents of the throw statement - new keyword' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_NEW, + 'expectedTarget' => T_THROW, + ], + 'Throw should be start for contents of the throw statement - exception name' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_THROW, + ], + 'Throw should be start for contents of the throw statement - close parenthesis' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_CLOSE_PARENTHESIS, + 'expectedTarget' => T_THROW, + ], + 'Goto should be start for contents of the goto statement - goto label' => [ + 'testMarker' => '/* testInsideCaseGotoStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_GOTO, + ], + 'Goto should be start for contents of the goto statement - semicolon' => [ + 'testMarker' => '/* testInsideCaseGotoStatement */', + 'targets' => T_SEMICOLON, + 'expectedTarget' => T_GOTO, + ], + 'Default keyword should be start of default statement - default itself' => [ + 'testMarker' => '/* testDefaultStatement */', + 'targets' => T_DEFAULT, + 'expectedTarget' => T_DEFAULT, + ], + 'Return should be start for contents of the return statement (inside default) - variable' => [ + 'testMarker' => '/* testInsideDefaultContinueStatement */', + 'targets' => T_VARIABLE, + 'expectedTarget' => T_CONTINUE, + ], + ]; + + }//end dataFindStartInsideSwitchCaseDefaultStatements() + + + /** + * Test finding the start of a statement inside a closed scope nested within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideClosedScopeNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideClosedScopeNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideClosedScopeNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideClosedScopeNestedWithinMatch() + { + return [ + // These were already working correctly. + 'Closure function keyword should be start of closure - closure keyword' => [ + 'testMarker' => '/* test437ClosureDeclaration */', + 'target' => T_CLOSURE, + 'expectedTarget' => T_CLOSURE, + ], + 'Open curly is a statement/expression opener - open curly' => [ + 'testMarker' => '/* test437ClosureDeclaration */', + 'target' => T_OPEN_CURLY_BRACKET, + 'expectedTarget' => T_OPEN_CURLY_BRACKET, + ], + + 'Echo should be start for expression - echo keyword' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_ECHO, + 'expectedTarget' => T_ECHO, + ], + 'Echo should be start for expression - variable' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_ECHO, + ], + 'Echo should be start for expression - comma' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_COMMA, + 'expectedTarget' => T_ECHO, + ], + + // These were not working correctly and would previously return the close curly of the match expression. + 'First token after comma in echo expression should be start for expression - text string' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_CONSTANT_ENCAPSED_STRING, + 'expectedTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'First token after comma in echo expression - PHP_EOL constant' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_STRING, + 'expectedTarget' => T_STRING, + ], + 'First token after comma in echo expression - semicolon' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_SEMICOLON, + 'expectedTarget' => T_STRING, + ], + ]; + + }//end dataFindStartInsideClosedScopeNestedWithinMatch() + + + /** + * Test finding the start of a statement for a token within a set of parentheses within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideParenthesesNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideParenthesesNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideParenthesesNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideParenthesesNestedWithinMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + + 'Parameter itself should be start for first param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Parameter itself should be start for second param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for third param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + + 'Parameter itself should be start for first param declared in arrow function' => [ + 'testMarker' => '/* test437NestedArrowFunctionWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for second param declared in arrow function' => [ + 'testMarker' => '/* test437FnSecondParamWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideParenthesesNestedWithinMatch() + + + /** + * Test finding the start of a statement for a token within a set of parentheses within a match expressions, + * which itself is nested within parentheses. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideParenthesesNestedWithinNestedMatch + * + * @return void + */ + public function testFindStartInsideParenthesesNestedWithinNestedMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideParenthesesNestedWithinNestedMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideParenthesesNestedWithinNestedMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + + 'Parameter itself should be start for first param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Parameter itself should be start for second param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for third param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + + 'Parameter itself should be start for first param declared in arrow function' => [ + 'testMarker' => '/* test437NestedArrowFunctionWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for second param declared in arrow function' => [ + 'testMarker' => '/* test437FnSecondParamWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideParenthesesNestedWithinNestedMatch() + + + /** + * Test finding the start of a statement for a token within a short array within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideShortArrayNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideShortArrayNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideShortArrayNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideShortArrayNestedWithinMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideShortArrayNestedWithinMatch() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc new file mode 100644 index 000000000..2490a0965 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc @@ -0,0 +1,58 @@ + + * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getClassProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getClassProperties + */ +final class GetClassPropertiesTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non class token is passed. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $tokenType The type of token to look for after the marker. + * + * @dataProvider dataNotAClassException + * + * @return void + */ + public function testNotAClassException($testMarker, $tokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_CLASS'); + + $target = $this->getTargetToken($testMarker, $tokenType); + self::$phpcsFile->getClassProperties($target); + + }//end testNotAClassException() + + + /** + * Data provider. + * + * @see testNotAClassException() For the array format. + * + * @return array> + */ + public static function dataNotAClassException() + { + return [ + 'interface' => [ + 'testMarker' => '/* testNotAClass */', + 'tokenType' => T_INTERFACE, + ], + 'anon-class' => [ + 'testMarker' => '/* testAnonClass */', + 'tokenType' => T_ANON_CLASS, + ], + 'enum' => [ + 'testMarker' => '/* testEnum */', + 'tokenType' => T_ENUM, + ], + ]; + + }//end dataNotAClassException() + + + /** + * Test retrieving the properties for a class declaration. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected Expected function output. + * + * @dataProvider dataGetClassProperties + * + * @return void + */ + public function testGetClassProperties($testMarker, $expected) + { + $class = $this->getTargetToken($testMarker, T_CLASS); + $result = self::$phpcsFile->getClassProperties($class); + $this->assertSame($expected, $result); + + }//end testGetClassProperties() + + + /** + * Data provider. + * + * @see testGetClassProperties() For the array format. + * + * @return array>> + */ + public static function dataGetClassProperties() + { + return [ + 'no-properties' => [ + 'testMarker' => '/* testClassWithoutProperties */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'abstract' => [ + 'testMarker' => '/* testAbstractClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'final' => [ + 'testMarker' => '/* testFinalClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => false, + ], + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'final-readonly' => [ + 'testMarker' => '/* testFinalReadonlyClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'readonly-final' => [ + 'testMarker' => '/* testReadonlyFinalClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'abstract-readonly' => [ + 'testMarker' => '/* testAbstractReadonlyClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'readonly-abstract' => [ + 'testMarker' => '/* testReadonlyAbstractClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'comments-and-new-lines' => [ + 'testMarker' => '/* testWithCommentsAndNewLines */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'no-properties-with-docblock' => [ + 'testMarker' => '/* testWithDocblockWithoutProperties */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'abstract-final-parse-error' => [ + 'testMarker' => '/* testParseErrorAbstractFinal */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => true, + 'is_readonly' => false, + ], + ], + ]; + + }//end dataGetClassProperties() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc new file mode 100644 index 000000000..e7684daa9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc @@ -0,0 +1,91 @@ + $v) { + + /* condition 11-2: try */ + try { + --$k; + + /* condition 11-3: catch */ + } catch (Exception $e) { + /* testInException */ + echo 'oh darn'; + /* condition 11-4: finally */ + } finally { + return true; + } + } + + $a++; + } + break; + + /* condition 8b: default */ + default: + /* testInDefault */ + $return = 'nada'; + return $return; + } + } + } + } + } + } + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php new file mode 100644 index 000000000..656bd64bb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php @@ -0,0 +1,494 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getCondition and \PHP_CodeSniffer\Files\File:hasCondition methods. + * + * @covers \PHP_CodeSniffer\Files\File::getCondition + * @covers \PHP_CodeSniffer\Files\File::hasCondition + */ +final class GetConditionTest extends AbstractMethodUnitTest +{ + + /** + * List of all the test markers with their target token in the test case file. + * + * - The startPoint token is left out as it is tested separately. + * - The key is the type of token to look for after the test marker. + * + * @var array + */ + protected static $testTargets = [ + T_VARIABLE => '/* testSeriouslyNestedMethod */', + T_RETURN => '/* testDeepestNested */', + T_ECHO => '/* testInException */', + T_CONSTANT_ENCAPSED_STRING => '/* testInDefault */', + ]; + + /** + * List of all the condition markers in the test case file. + * + * @var array + */ + protected $conditionMarkers = [ + '/* condition 0: namespace */', + '/* condition 1: if */', + '/* condition 2: function */', + '/* condition 3-1: if */', + '/* condition 3-2: else */', + '/* condition 4: if */', + '/* condition 5: nested class */', + '/* condition 6: class method */', + '/* condition 7: switch */', + '/* condition 8a: case */', + '/* condition 9: while */', + '/* condition 10-1: if */', + '/* condition 11-1: nested anonymous class */', + '/* condition 12: nested anonymous class method */', + '/* condition 13: closure */', + '/* condition 10-2: elseif */', + '/* condition 10-3: foreach */', + '/* condition 11-2: try */', + '/* condition 11-3: catch */', + '/* condition 11-4: finally */', + '/* condition 8b: default */', + ]; + + /** + * Base array with all the scope opening tokens. + * + * This array is merged with expected result arrays for various unit tests + * to make sure all possible conditions are tested. + * + * This array should be kept in sync with the Tokens::$scopeOpeners array. + * This array isn't auto-generated based on the array in Tokens as for these + * tests we want to have access to the token constant names, not just their values. + * + * @var array + */ + protected $conditionDefaults = [ + 'T_CLASS' => false, + 'T_ANON_CLASS' => false, + 'T_INTERFACE' => false, + 'T_TRAIT' => false, + 'T_NAMESPACE' => false, + 'T_FUNCTION' => false, + 'T_CLOSURE' => false, + 'T_IF' => false, + 'T_SWITCH' => false, + 'T_CASE' => false, + 'T_DECLARE' => false, + 'T_DEFAULT' => false, + 'T_WHILE' => false, + 'T_ELSE' => false, + 'T_ELSEIF' => false, + 'T_FOR' => false, + 'T_FOREACH' => false, + 'T_DO' => false, + 'T_TRY' => false, + 'T_CATCH' => false, + 'T_FINALLY' => false, + 'T_PROPERTY' => false, + 'T_OBJECT' => false, + 'T_USE' => false, + ]; + + /** + * Cache for the test token stack pointers. + * + * @var array + */ + protected static $testTokens = []; + + /** + * Cache for the marker token stack pointers. + * + * @var array + */ + protected static $markerTokens = []; + + + /** + * Set up the token position caches for the tests. + * + * Retrieves the test tokens and marker token stack pointer positions + * only once and caches them as they won't change between the tests anyway. + * + * @before + * + * @return void + */ + protected function setUpCaches() + { + if (empty(self::$testTokens) === true) { + foreach (self::$testTargets as $targetToken => $marker) { + self::$testTokens[$marker] = $this->getTargetToken($marker, $targetToken); + } + } + + if (empty(self::$markerTokens) === true) { + foreach ($this->conditionMarkers as $marker) { + self::$markerTokens[$marker] = $this->getTargetToken($marker, Tokens::$scopeOpeners); + } + } + + }//end setUpCaches() + + + /** + * Test passing a non-existent token pointer. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->getCondition(100000, T_CLASS); + $this->assertFalse($result); + + $result = self::$phpcsFile->hasCondition(100000, T_IF); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test passing a non conditional token. + * + * @return void + */ + public function testNonConditionalToken() + { + $targetType = T_STRING; + $stackPtr = $this->getTargetToken('/* testStartPoint */', $targetType); + + $result = self::$phpcsFile->getCondition($stackPtr, T_IF); + $this->assertFalse($result); + + $result = self::$phpcsFile->hasCondition($stackPtr, Tokens::$ooScopeTokens); + $this->assertFalse($result); + + }//end testNonConditionalToken() + + + /** + * Test retrieving a specific condition from a tokens "conditions" array. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the marker for the expected stack pointer result as a value. + * + * @dataProvider dataGetCondition + * + * @return void + */ + public function testGetCondition($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + if (is_string($expected) === true) { + $expected = self::$markerTokens[$expected]; + } + + $result = self::$phpcsFile->getCondition($stackPtr, constant($conditionType)); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType}" + ); + } + + }//end testGetCondition() + + + /** + * Data provider. + * + * Only the conditions which are expected to be *found* need to be listed here. + * All other potential conditions will automatically also be tested and will expect + * `false` as a result. + * + * @see testGetCondition() For the array format. + * + * @return array>> + */ + public static function dataGetCondition() + { + return [ + 'testSeriouslyNestedMethod' => [ + 'testMarker' => '/* testSeriouslyNestedMethod */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + 'testDeepestNested' => [ + 'testMarker' => '/* testDeepestNested */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_ANON_CLASS' => '/* condition 11-1: nested anonymous class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_CLOSURE' => '/* condition 13: closure */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_CASE' => '/* condition 8a: case */', + 'T_WHILE' => '/* condition 9: while */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + 'testInException' => [ + 'testMarker' => '/* testInException */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_CASE' => '/* condition 8a: case */', + 'T_WHILE' => '/* condition 9: while */', + 'T_ELSE' => '/* condition 3-2: else */', + 'T_FOREACH' => '/* condition 10-3: foreach */', + 'T_CATCH' => '/* condition 11-3: catch */', + ], + ], + 'testInDefault' => [ + 'testMarker' => '/* testInDefault */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_DEFAULT' => '/* condition 8b: default */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + ]; + + }//end dataGetCondition() + + + /** + * Test retrieving a specific condition from a tokens "conditions" array. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the marker for the expected stack pointer result as a value. + * + * @dataProvider dataGetConditionReversed + * + * @return void + */ + public function testGetConditionReversed($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + if (is_string($expected) === true) { + $expected = self::$markerTokens[$expected]; + } + + $result = self::$phpcsFile->getCondition($stackPtr, constant($conditionType), false); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType} (reversed)" + ); + } + + }//end testGetConditionReversed() + + + /** + * Data provider. + * + * Only the conditions which are expected to be *found* need to be listed here. + * All other potential conditions will automatically also be tested and will expect + * `false` as a result. + * + * @see testGetConditionReversed() For the array format. + * + * @return array>> + */ + public static function dataGetConditionReversed() + { + $data = self::dataGetCondition(); + + // Set up the data for the reversed results. + $data['testSeriouslyNestedMethod']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + $data['testDeepestNested']['expectedResults']['T_FUNCTION'] = '/* condition 12: nested anonymous class method */'; + $data['testDeepestNested']['expectedResults']['T_IF'] = '/* condition 10-1: if */'; + + $data['testInException']['expectedResults']['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInException']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + $data['testInDefault']['expectedResults']['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInDefault']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + return $data; + + }//end dataGetConditionReversed() + + + /** + * Test whether a token has a condition of a certain type. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the expected result as a value. + * + * @dataProvider dataHasCondition + * + * @return void + */ + public function testHasCondition($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + $result = self::$phpcsFile->hasCondition($stackPtr, constant($conditionType)); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType}" + ); + } + + }//end testHasCondition() + + + /** + * Data Provider. + * + * Only list the "true" conditions in the $results array. + * All other potential conditions will automatically also be tested + * and will expect "false" as a result. + * + * @see testHasCondition() For the array format. + * + * @return array>> + */ + public static function dataHasCondition() + { + return [ + 'testSeriouslyNestedMethod' => [ + 'testMarker' => '/* testSeriouslyNestedMethod */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_ELSE' => true, + ], + ], + 'testDeepestNested' => [ + 'testMarker' => '/* testDeepestNested */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_ANON_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_CLOSURE' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_CASE' => true, + 'T_WHILE' => true, + 'T_ELSE' => true, + ], + ], + 'testInException' => [ + 'testMarker' => '/* testInException */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_CASE' => true, + 'T_WHILE' => true, + 'T_ELSE' => true, + 'T_FOREACH' => true, + 'T_CATCH' => true, + ], + ], + 'testInDefault' => [ + 'testMarker' => '/* testInDefault */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_DEFAULT' => true, + 'T_ELSE' => true, + ], + ], + ]; + + }//end dataHasCondition() + + + /** + * Test whether a token has a condition of a certain type, with multiple allowed possibilities. + * + * @return void + */ + public function testHasConditionMultipleTypes() + { + $stackPtr = self::$testTokens['/* testInException */']; + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_TRY, T_FINALLY]); + $this->assertFalse( + $result, + 'Failed asserting that "testInException" does not have a "try" nor a "finally" condition' + ); + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_TRY, T_CATCH, T_FINALLY]); + $this->assertTrue( + $result, + 'Failed asserting that "testInException" has a "try", "catch" or "finally" condition' + ); + + $stackPtr = self::$testTokens['/* testSeriouslyNestedMethod */']; + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_ANON_CLASS, T_CLOSURE]); + $this->assertFalse( + $result, + 'Failed asserting that "testSeriouslyNestedMethod" does not have an anonymous class nor a closure condition' + ); + + $result = self::$phpcsFile->hasCondition($stackPtr, Tokens::$ooScopeTokens); + $this->assertTrue( + $result, + 'Failed asserting that "testSeriouslyNestedMethod" has an OO Scope token condition' + ); + + }//end testHasConditionMultipleTypes() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js new file mode 100644 index 000000000..ee0a76a44 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js @@ -0,0 +1,23 @@ +/* testInvalidTokenPassed */ +print something; + +var object = +{ + /* testClosure */ + propertyName: function () {} +} + +/* testFunction */ +function functionName() {} + +/* testClass */ +class ClassName +{ + /* testMethod */ + methodName() { + return false; + } +} + +/* testFunctionUnicode */ +function π() {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php new file mode 100644 index 000000000..af3fe56d2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php @@ -0,0 +1,158 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameJSTest extends AbstractMethodUnitTest +{ + + /** + * The file extension of the test case file (without leading dot). + * + * @var string + */ + protected static $fileExtension = 'js'; + + + /** + * Test receiving an expected exception when a non-supported token is passed. + * + * @return void + */ + public function testInvalidTokenPassed() + { + $this->expectRunTimeException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); + + $target = $this->getTargetToken('/* testInvalidTokenPassed */', T_STRING); + self::$phpcsFile->getDeclarationName($target); + + }//end testInvalidTokenPassed() + + + /** + * Test receiving "null" when passed an anonymous construct or in case of a parse error. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationNameNull + * + * @return void + */ + public function testGetDeclarationNameNull($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + + /** + * Data provider. + * + * @see GetDeclarationNameTest::testGetDeclarationNameNull() + * + * @return array> + */ + public static function dataGetDeclarationNameNull() + { + return [ + 'closure' => [ + 'testMarker' => '/* testClosure */', + 'targetType' => T_CLOSURE, + ], + ]; + + }//end dataGetDeclarationNameNull() + + + /** + * Test retrieving the name of a function or OO structure. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected Expected function output. + * @param array|null $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationName + * + * @return void + */ + public function testGetDeclarationName($testMarker, $expected, $targetType=null) + { + if (isset($targetType) === false) { + $targetType = [ + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_ENUM, + T_FUNCTION, + ]; + } + + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame($expected, $result); + + }//end testGetDeclarationName() + + + /** + * Data provider. + * + * @see GetDeclarationNameTest::testGetDeclarationName() + * + * @return array>> + */ + public static function dataGetDeclarationName() + { + return [ + 'function' => [ + 'testMarker' => '/* testFunction */', + 'expected' => 'functionName', + ], + 'class' => [ + 'testMarker' => '/* testClass */', + 'expected' => 'ClassName', + 'targetType' => [ + T_CLASS, + T_STRING, + ], + ], + 'function-unicode-name' => [ + 'testMarker' => '/* testFunctionUnicode */', + 'expected' => 'π', + ], + ]; + + }//end dataGetDeclarationName() + + + /** + * Test retrieving the name of JS ES6 class method. + * + * @return void + */ + public function testGetDeclarationNameES6Method() + { + $target = $this->getTargetToken('/* testMethod */', [T_CLASS, T_INTERFACE, T_TRAIT, T_FUNCTION]); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame('methodName', $result); + + }//end testGetDeclarationNameES6Method() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameParseError1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameParseError1Test.inc new file mode 100644 index 000000000..451d4dfb8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameParseError1Test.inc @@ -0,0 +1,5 @@ + + * @copyright 2025 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameParseError1Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving "null" in case of a parse error. + * + * @return void + */ + public function testGetDeclarationNameNull() + { + $target = $this->getTargetToken('/* testLiveCoding */', T_FUNCTION); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameParseError2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameParseError2Test.inc new file mode 100644 index 000000000..e9a61cf41 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameParseError2Test.inc @@ -0,0 +1,6 @@ + + * @copyright 2025 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameParseError2Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving "null" in case of a parse error. + * + * @return void + */ + public function testGetDeclarationNameNull() + { + $target = $this->getTargetToken('/* testLiveCoding */', T_FUNCTION); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc new file mode 100644 index 000000000..a7a53c9a1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc @@ -0,0 +1,98 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non-supported token is passed. + * + * @return void + */ + public function testInvalidTokenPassed() + { + $this->expectRunTimeException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); + + $target = $this->getTargetToken('/* testInvalidTokenPassed */', T_STRING); + self::$phpcsFile->getDeclarationName($target); + + }//end testInvalidTokenPassed() + + + /** + * Test receiving "null" when passed an anonymous construct or in case of a parse error. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationNameNull + * + * @return void + */ + public function testGetDeclarationNameNull($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + + /** + * Data provider. + * + * @see testGetDeclarationNameNull() For the array format. + * + * @return array> + */ + public static function dataGetDeclarationNameNull() + { + return [ + 'closure' => [ + 'testMarker' => '/* testClosure */', + 'targetType' => T_CLOSURE, + ], + 'anon-class-with-parentheses' => [ + 'testMarker' => '/* testAnonClassWithParens */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-with-parentheses-2' => [ + 'testMarker' => '/* testAnonClassWithParens2 */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-without-parentheses' => [ + 'testMarker' => '/* testAnonClassWithoutParens */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-extends-without-parentheses' => [ + 'testMarker' => '/* testAnonClassExtendsWithoutParens */', + 'targetType' => T_ANON_CLASS, + ], + ]; + + }//end dataGetDeclarationNameNull() + + + /** + * Test retrieving the name of a function or OO structure. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected Expected function output. + * @param int|string|null $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationName + * + * @return void + */ + public function testGetDeclarationName($testMarker, $expected, $targetType=null) + { + if (isset($targetType) === false) { + $targetType = [ + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_ENUM, + T_FUNCTION, + ]; + } + + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame($expected, $result); + + }//end testGetDeclarationName() + + + /** + * Data provider. + * + * @see testGetDeclarationName() For the array format. + * + * @return array> + */ + public static function dataGetDeclarationName() + { + return [ + 'function' => [ + 'testMarker' => '/* testFunction */', + 'expected' => 'functionName', + ], + 'function-return-by-reference' => [ + 'testMarker' => '/* testFunctionReturnByRef */', + 'expected' => 'functionNameByRef', + ], + 'class' => [ + 'testMarker' => '/* testClass */', + 'expected' => 'ClassName', + ], + 'method' => [ + 'testMarker' => '/* testMethod */', + 'expected' => 'methodName', + ], + 'abstract-method' => [ + 'testMarker' => '/* testAbstractMethod */', + 'expected' => 'abstractMethodName', + ], + 'method-return-by-reference' => [ + 'testMarker' => '/* testMethodReturnByRef */', + 'expected' => 'MethodNameByRef', + ], + 'extended-class' => [ + 'testMarker' => '/* testExtendedClass */', + 'expected' => 'ExtendedClass', + ], + 'interface' => [ + 'testMarker' => '/* testInterface */', + 'expected' => 'InterfaceName', + ], + 'trait' => [ + 'testMarker' => '/* testTrait */', + 'expected' => 'TraitName', + ], + 'function-name-ends-with-number' => [ + 'testMarker' => '/* testFunctionEndingWithNumber */', + 'expected' => 'ValidNameEndingWithNumber5', + ], + 'class-with-numbers-in-name' => [ + 'testMarker' => '/* testClassWithNumber */', + 'expected' => 'ClassWith1Number', + ], + 'interface-with-numbers-in-name' => [ + 'testMarker' => '/* testInterfaceWithNumbers */', + 'expected' => 'InterfaceWith12345Numbers', + ], + 'class-with-comments-and-new-lines' => [ + 'testMarker' => '/* testClassWithCommentsAndNewLines */', + 'expected' => 'ClassWithCommentsAndNewLines', + ], + 'function-named-fn' => [ + 'testMarker' => '/* testFunctionFn */', + 'expected' => 'fn', + ], + 'enum-pure' => [ + 'testMarker' => '/* testPureEnum */', + 'expected' => 'Foo', + ], + 'enum-backed-space-between-name-and-colon' => [ + 'testMarker' => '/* testBackedEnumSpaceBetweenNameAndColon */', + 'expected' => 'Hoo', + ], + 'enum-backed-no-space-between-name-and-colon' => [ + 'testMarker' => '/* testBackedEnumNoSpaceBetweenNameAndColon */', + 'expected' => 'Suit', + ], + 'function-return-by-reference-with-reserved-keyword-each' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordEach */', + 'expected' => 'each', + ], + 'function-return-by-reference-with-reserved-keyword-parent' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordParent */', + 'expected' => 'parent', + ], + 'function-return-by-reference-with-reserved-keyword-self' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordSelf */', + 'expected' => 'self', + ], + 'function-return-by-reference-with-reserved-keyword-static' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordStatic */', + 'expected' => 'static', + ], + ]; + + }//end dataGetDeclarationName() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc index f40b6021f..c85882660 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc @@ -39,7 +39,10 @@ class TestMemberProperties var static $varG = true; /* testPublicStatic */ - public static $varH = true; + public // comment + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + static + $varH = true; /* testProtectedStatic */ static protected $varI = true; @@ -210,18 +213,19 @@ $anon = class() { /* testPHP8UnionTypesIllegalTypes */ // Intentional fatal error - types which are not allowed for properties, but that's not the concern of the method. - public callable|static|void $unionTypesIllegalTypes; + // Note: static is also not allowed as a type, but using static for a property type is not supported by the tokenizer. + public callable|void $unionTypesIllegalTypes; /* testPHP8UnionTypesNullable */ // Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. public ?int|float $unionTypesNullable; /* testPHP8PseudoTypeNull */ - // Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. + // PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. public null $pseudoTypeNull; /* testPHP8PseudoTypeFalse */ - // Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. + // PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. public false $pseudoTypeFalse; /* testPHP8PseudoTypeFalseAndBool */ @@ -244,7 +248,7 @@ $anon = class() { public readonly int $readonly; /* testPHP81ReadonlyWithNullableType */ - public readonly ?array $array; + public readonly ?array $readonlyWithNullableType; /* testPHP81ReadonlyWithUnionType */ public readonly string|int $readonlyWithUnionType; @@ -254,6 +258,16 @@ $anon = class() { /* testPHP81OnlyReadonlyWithUnionType */ readonly string|int $onlyReadonly; + + /* testPHP81OnlyReadonlyWithUnionTypeMultiple */ + readonly \InterfaceA|\Sub\InterfaceB|false + $onlyReadonly; + + /* testPHP81ReadonlyAndStatic */ + readonly private static ?string $readonlyAndStatic; + + /* testPHP81ReadonlyMixedCase */ + public ReadONLY static $readonlyMixedCase; }; $anon = class { @@ -298,7 +312,66 @@ $anon = class() { // Intentional fatal error - types which are not allowed for intersection type, but that's not the concern of the method. public int&string $illegalIntersectionType; - /* testPHP81NulltableIntersectionType */ + /* testPHP81NullableIntersectionType */ // Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method. public ?Foo&Bar $nullableIntersectionType; }; + +$anon = class() { + /* testPHP82PseudoTypeTrue */ + public true $pseudoTypeTrue; + + /* testPHP82NullablePseudoTypeTrue */ + static protected ?true $pseudoTypeNullableTrue; + + /* testPHP82PseudoTypeTrueInUnion */ + private int|string|true $pseudoTypeTrueInUnion; + + /* testPHP82PseudoTypeFalseAndTrue */ + // Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. + readonly true|FALSE $pseudoTypeFalseAndTrue; +}; + +class WhitespaceAndCommentsInTypes { + /* testUnionTypeWithWhitespaceAndComment */ + public int | /*comment*/ string $hasWhitespaceAndComment; + + /* testIntersectionTypeWithWhitespaceAndComment */ + public \Foo /*comment*/ & Bar $hasWhitespaceAndComment; +} + +trait DNFTypes { + /* testPHP82DNFTypeStatic */ + public static (Foo&\Bar)|bool $propA; + + /* testPHP82DNFTypeReadonlyA */ + protected readonly float|(Partially\Qualified&Traversable) $propB; + + /* testPHP82DNFTypeReadonlyB */ + private readonly (namespace\Foo&Bar)|string $propC; + + /* testPHP82DNFTypeIllegalNullable */ + // Intentional fatal error - nullable operator cannot be combined with DNF. + var ?(A&\Pck\B)|bool $propD; +} + +class WithFinalProperties { + /* testPHP84FinalPublicTypedProp */ + final public string $val1; + /* testPHP84FinalProtectedTypedProp */ + final protected string $val2; + /* testPHP84FinalMiddleTypedProp */ + public final string $val3; + /* testPHP84FinalMiddleStaticTypedProp */ + public final static string $val4; + /* testPHP84FinalLastTypedProp */ + public readonly final string $val5; + /* testPHP84FinalImplicitVisibilityTypedProp */ + final string $val6; + /* testPHP84FinalImplicitVisibilityProp */ + final $val7; + /* testPHP84FinalNullableTypedProp */ + final public ?string $val8; + /* testPHP84FinalComplexTypedProp */ + final public (Foo&\Bar)|bool $val9; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php index 934d8e289..53cfe5f3d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php @@ -4,22 +4,27 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class GetMemberPropertiesTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMemberProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getMemberProperties + */ +final class GetMemberPropertiesTest extends AbstractMethodUnitTest { /** * Test the getMemberProperties() method. * - * @param string $identifier Comment which precedes the test case. - * @param bool $expected Expected function output. + * @param string $identifier Comment which precedes the test case. + * @param array $expected Expected function output. * * @dataProvider dataGetMemberProperties * @@ -30,7 +35,16 @@ public function testGetMemberProperties($identifier, $expected) $variable = $this->getTargetToken($identifier, T_VARIABLE); $result = self::$phpcsFile->getMemberProperties($variable); - $this->assertArraySubset($expected, $result, true); + // Convert offsets to absolute positions in the token stream. + if (isset($expected['type_token']) === true && is_int($expected['type_token']) === true) { + $expected['type_token'] += $variable; + } + + if (isset($expected['type_end_token']) === true && is_int($expected['type_end_token']) === true) { + $expected['type_end_token'] += $variable; + } + + $this->assertSame($expected, $result); }//end testGetMemberProperties() @@ -38,766 +52,1288 @@ public function testGetMemberProperties($identifier, $expected) /** * Data provider for the GetMemberProperties test. * + * Note: the `expected - type_token` and `expected - type_end_token` indexes should + * contain either `false` (no type) or the _offset_ of the type start/end token in + * relation to the `T_VARIABLE` token which is passed to the getMemberProperties() method. + * * @see testGetMemberProperties() * - * @return array + * @return array>> */ - public function dataGetMemberProperties() + public static function dataGetMemberProperties() { return [ - [ - '/* testVar */', - [ + 'var-modifier' => [ + 'identifier' => '/* testVar */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testVarType */', - [ + 'var-modifier-and-type' => [ + 'identifier' => '/* testVarType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?int', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPublic */', - [ + 'public-modifier' => [ + 'identifier' => '/* testPublic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPublicType */', - [ + 'public-modifier-and-type' => [ + 'identifier' => '/* testPublicType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testProtected */', - [ + 'protected-modifier' => [ + 'identifier' => '/* testProtected */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testProtectedType */', - [ + 'protected-modifier-and-type' => [ + 'identifier' => '/* testProtectedType */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'bool', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPrivate */', - [ + 'private-modifier' => [ + 'identifier' => '/* testPrivate */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPrivateType */', - [ + 'private-modifier-and-type' => [ + 'identifier' => '/* testPrivateType */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'array', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testStatic */', - [ + 'static-modifier' => [ + 'identifier' => '/* testStatic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testStaticType */', - [ + 'static-modifier-and-type' => [ + 'identifier' => '/* testStaticType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testStaticVar */', - [ + 'static-and-var-modifier' => [ + 'identifier' => '/* testStaticVar */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testVarStatic */', - [ + 'var-and-static-modifier' => [ + 'identifier' => '/* testVarStatic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPublicStatic */', - [ + 'public-static-modifiers' => [ + 'identifier' => '/* testPublicStatic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testProtectedStatic */', - [ + 'protected-static-modifiers' => [ + 'identifier' => '/* testProtectedStatic */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPrivateStatic */', - [ + 'private-static-modifiers' => [ + 'identifier' => '/* testPrivateStatic */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testNoPrefix */', - [ + 'no-modifier' => [ + 'identifier' => '/* testNoPrefix */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPublicStaticWithDocblock */', - [ + 'public-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testPublicStaticWithDocblock */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testProtectedStaticWithDocblock */', - [ + 'protected-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testProtectedStaticWithDocblock */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPrivateStaticWithDocblock */', - [ + 'private-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testPrivateStaticWithDocblock */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupType 1 */', - [ + 'property-group-simple-type-prop-1' => [ + 'identifier' => '/* testGroupType 1 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'float', + 'type_token' => -6, + 'type_end_token' => -6, 'nullable_type' => false, ], ], - [ - '/* testGroupType 2 */', - [ + 'property-group-simple-type-prop-2' => [ + 'identifier' => '/* testGroupType 2 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'float', + 'type_token' => -13, + 'type_end_token' => -13, 'nullable_type' => false, ], ], - [ - '/* testGroupNullableType 1 */', - [ + 'property-group-nullable-type-prop-1' => [ + 'identifier' => '/* testGroupNullableType 1 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '?string', + 'type_token' => -6, + 'type_end_token' => -6, 'nullable_type' => true, ], ], - [ - '/* testGroupNullableType 2 */', - [ + 'property-group-nullable-type-prop-2' => [ + 'identifier' => '/* testGroupNullableType 2 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '?string', + 'type_token' => -17, + 'type_end_token' => -17, 'nullable_type' => true, ], ], - [ - '/* testGroupProtectedStatic 1 */', - [ + 'property-group-protected-static-prop-1' => [ + 'identifier' => '/* testGroupProtectedStatic 1 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupProtectedStatic 2 */', - [ + 'property-group-protected-static-prop-2' => [ + 'identifier' => '/* testGroupProtectedStatic 2 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupProtectedStatic 3 */', - [ + 'property-group-protected-static-prop-3' => [ + 'identifier' => '/* testGroupProtectedStatic 3 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 1 */', - [ + 'property-group-private-prop-1' => [ + 'identifier' => '/* testGroupPrivate 1 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 2 */', - [ + 'property-group-private-prop-2' => [ + 'identifier' => '/* testGroupPrivate 2 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 3 */', - [ + 'property-group-private-prop-3' => [ + 'identifier' => '/* testGroupPrivate 3 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 4 */', - [ + 'property-group-private-prop-4' => [ + 'identifier' => '/* testGroupPrivate 4 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 5 */', - [ + 'property-group-private-prop-5' => [ + 'identifier' => '/* testGroupPrivate 5 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 6 */', - [ + 'property-group-private-prop-6' => [ + 'identifier' => '/* testGroupPrivate 6 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 7 */', - [ + 'property-group-private-prop-7' => [ + 'identifier' => '/* testGroupPrivate 7 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testMessyNullableType */', - [ + 'messy-nullable-type' => [ + 'identifier' => '/* testMessyNullableType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?array', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testNamespaceType */', - [ + 'fqn-type' => [ + 'identifier' => '/* testNamespaceType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '\MyNamespace\MyClass', + 'type_token' => -5, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testNullableNamespaceType 1 */', - [ + 'nullable-classname-type' => [ + 'identifier' => '/* testNullableNamespaceType 1 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?ClassName', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testNullableNamespaceType 2 */', - [ + 'nullable-namespace-relative-class-type' => [ + 'identifier' => '/* testNullableNamespaceType 2 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?Folder\ClassName', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testMultilineNamespaceType */', - [ + 'multiline-namespaced-type' => [ + 'identifier' => '/* testMultilineNamespaceType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '\MyNamespace\MyClass\Foo', + 'type_token' => -18, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPropertyAfterMethod */', - [ + 'property-after-method' => [ + 'identifier' => '/* testPropertyAfterMethod */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testInterfaceProperty */', - [], + 'invalid-property-in-interface' => [ + 'identifier' => '/* testInterfaceProperty */', + 'expected' => [], ], - [ - '/* testNestedProperty 1 */', - [ + 'property-in-nested-class-1' => [ + 'identifier' => '/* testNestedProperty 1 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testNestedProperty 2 */', - [ + 'property-in-nested-class-2' => [ + 'identifier' => '/* testNestedProperty 2 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPHP8MixedTypeHint */', - [ + 'php8-mixed-type' => [ + 'identifier' => '/* testPHP8MixedTypeHint */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => 'miXed', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8MixedTypeHintNullable */', - [ + 'php8-nullable-mixed-type' => [ + 'identifier' => '/* testPHP8MixedTypeHintNullable */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?mixed', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testNamespaceOperatorTypeHint */', - [ + 'namespace-operator-type-declaration' => [ + 'identifier' => '/* testNamespaceOperatorTypeHint */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?namespace\Name', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP8UnionTypesSimple */', - [ + 'php8-union-types-simple' => [ + 'identifier' => '/* testPHP8UnionTypesSimple */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'int|float', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesTwoClasses */', - [ + 'php8-union-types-two-classes' => [ + 'identifier' => '/* testPHP8UnionTypesTwoClasses */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'MyClassA|\Package\MyClassB', + 'type_token' => -7, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesAllBaseTypes */', - [ + 'php8-union-types-all-base-types' => [ + 'identifier' => '/* testPHP8UnionTypesAllBaseTypes */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'array|bool|int|float|NULL|object|string', + 'type_token' => -14, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesAllPseudoTypes */', - [ + 'php8-union-types-all-pseudo-types' => [ + 'identifier' => '/* testPHP8UnionTypesAllPseudoTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'false|mixed|self|parent|iterable|Resource', + 'type_token' => -12, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesIllegalTypes */', - [ + 'php8-union-types-illegal-types' => [ + 'identifier' => '/* testPHP8UnionTypesIllegalTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, // Missing static, but that's OK as not an allowed syntax. - 'type' => 'callable||void', + 'type' => 'callable|void', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesNullable */', - [ + 'php8-union-types-nullable' => [ + 'identifier' => '/* testPHP8UnionTypesNullable */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?int|float', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP8PseudoTypeNull */', - [ + 'php8-union-types-pseudo-type-null' => [ + 'identifier' => '/* testPHP8PseudoTypeNull */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'null', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PseudoTypeFalse */', - [ + 'php8-union-types-pseudo-type-false' => [ + 'identifier' => '/* testPHP8PseudoTypeFalse */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'false', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PseudoTypeFalseAndBool */', - [ + 'php8-union-types-pseudo-type-false-and-bool' => [ + 'identifier' => '/* testPHP8PseudoTypeFalseAndBool */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'bool|FALSE', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8ObjectAndClass */', - [ + 'php8-union-types-object-and-class' => [ + 'identifier' => '/* testPHP8ObjectAndClass */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'object|ClassName', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PseudoTypeIterableAndArray */', - [ + 'php8-union-types-pseudo-type-iterable-and-array' => [ + 'identifier' => '/* testPHP8PseudoTypeIterableAndArray */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'iterable|array|Traversable', + 'type_token' => -6, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */', - [ + 'php8-union-types-duplicate-type-with-whitespace-and-comments' => [ + 'identifier' => '/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'int|string|INT', + 'type_token' => -10, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81Readonly */', - [ + 'php8.1-readonly-property' => [ + 'identifier' => '/* testPHP81Readonly */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'int', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81ReadonlyWithNullableType */', - [ + 'php8.1-readonly-property-with-nullable-type' => [ + 'identifier' => '/* testPHP81ReadonlyWithNullableType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => '?array', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP81ReadonlyWithUnionType */', - [ + 'php8.1-readonly-property-with-union-type' => [ + 'identifier' => '/* testPHP81ReadonlyWithUnionType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81ReadonlyWithUnionTypeWithNull */', - [ + 'php8.1-readonly-property-with-union-type-with-null' => [ + 'identifier' => '/* testPHP81ReadonlyWithUnionTypeWithNull */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'string|null', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81OnlyReadonlyWithUnionType */', - [ + 'php8.1-readonly-property-with-union-type-no-visibility' => [ + 'identifier' => '/* testPHP81OnlyReadonlyWithUnionType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-multi-union-type-no-visibility' => [ + 'identifier' => '/* testPHP81OnlyReadonlyWithUnionTypeMultiple */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '\InterfaceA|\Sub\InterfaceB|false', + 'type_token' => -11, + 'type_end_token' => -3, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-and-static-property' => [ + 'identifier' => '/* testPHP81ReadonlyAndStatic */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.1-readonly-mixed-case-keyword' => [ + 'identifier' => '/* testPHP81ReadonlyMixedCase */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPHP8PropertySingleAttribute */', - [ + 'php8-property-with-single-attribute' => [ + 'identifier' => '/* testPHP8PropertySingleAttribute */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PropertyMultipleAttributes */', - [ + 'php8-property-with-multiple-attributes' => [ + 'identifier' => '/* testPHP8PropertyMultipleAttributes */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?int|float', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP8PropertyMultilineAttribute */', - [ + 'php8-property-with-multiline-attribute' => [ + 'identifier' => '/* testPHP8PropertyMultilineAttribute */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testEnumProperty */', - [], + 'invalid-property-in-enum' => [ + 'identifier' => '/* testEnumProperty */', + 'expected' => [], ], - [ - '/* testPHP81IntersectionTypes */', - [ + 'php8.1-single-intersection-type' => [ + 'identifier' => '/* testPHP81IntersectionTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, 'type' => 'Foo&Bar', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81MoreIntersectionTypes */', - [ + 'php8.1-multi-intersection-type' => [ + 'identifier' => '/* testPHP81MoreIntersectionTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, 'type' => 'Foo&Bar&Baz', + 'type_token' => -6, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81IllegalIntersectionTypes */', - [ + 'php8.1-illegal-intersection-type' => [ + 'identifier' => '/* testPHP81IllegalIntersectionTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, 'type' => 'int&string', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81NulltableIntersectionType */', - [ + 'php8.1-nullable-intersection-type' => [ + 'identifier' => '/* testPHP81NullableIntersectionType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, 'type' => '?Foo&Bar', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + + 'php8.0-union-type-with-whitespace-and-comment' => [ + 'identifier' => '/* testUnionTypeWithWhitespaceAndComment */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'int|string', + 'type_token' => -8, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-intersection-type-with-whitespace-and-comment' => [ + 'identifier' => '/* testIntersectionTypeWithWhitespaceAndComment */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '\Foo&Bar', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-true' => [ + 'identifier' => '/* testPHP82PseudoTypeTrue */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'true', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-true-nullable' => [ + 'identifier' => '/* testPHP82NullablePseudoTypeTrue */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?true', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], + 'php8.2-pseudo-type-true-in-union' => [ + 'identifier' => '/* testPHP82PseudoTypeTrueInUnion */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'int|string|true', + 'type_token' => -6, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-invalid-true-false-union' => [ + 'identifier' => '/* testPHP82PseudoTypeFalseAndTrue */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'true|FALSE', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + + 'php8.2-dnf-with-static' => [ + 'identifier' => '/* testPHP82DNFTypeStatic */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '(Foo&\Bar)|bool', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-readonly-1' => [ + 'identifier' => '/* testPHP82DNFTypeReadonlyA */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'float|(Partially\Qualified&Traversable)', + 'type_token' => -10, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-readonly-2' => [ + 'identifier' => '/* testPHP82DNFTypeReadonlyB */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '(namespace\Foo&Bar)|string', + 'type_token' => -10, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-illegal-nullable' => [ + 'identifier' => '/* testPHP82DNFTypeIllegalNullable */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?(A&\Pck\B)|bool', + 'type_token' => -11, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-final-public-property' => [ + 'identifier' => '/* testPHP84FinalPublicTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-protected-property' => [ + 'identifier' => '/* testPHP84FinalProtectedTypedProp */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-middle-keyword-property' => [ + 'identifier' => '/* testPHP84FinalMiddleTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-middle-keyword-static-property' => [ + 'identifier' => '/* testPHP84FinalMiddleStaticTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-last-keyword-property' => [ + 'identifier' => '/* testPHP84FinalLastTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-implicit-public-typed-property' => [ + 'identifier' => '/* testPHP84FinalImplicitVisibilityTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-implicit-public-untyped-property' => [ + 'identifier' => '/* testPHP84FinalImplicitVisibilityProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8.4-final-public-nullable-typed-property' => [ + 'identifier' => '/* testPHP84FinalNullableTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-final-public-complex-type-property' => [ + 'identifier' => '/* testPHP84FinalComplexTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '(Foo&\Bar)|bool', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], ]; }//end dataGetMemberProperties() @@ -808,17 +1344,16 @@ public function dataGetMemberProperties() * * @param string $identifier Comment which precedes the test case. * - * @expectedException PHP_CodeSniffer\Exceptions\RuntimeException - * @expectedExceptionMessage $stackPtr is not a class member var - * * @dataProvider dataNotClassProperty * * @return void */ public function testNotClassPropertyException($identifier) { + $this->expectRunTimeException('$stackPtr is not a class member var'); + $variable = $this->getTargetToken($identifier, T_VARIABLE); - $result = self::$phpcsFile->getMemberProperties($variable); + self::$phpcsFile->getMemberProperties($variable); }//end testNotClassPropertyException() @@ -828,18 +1363,18 @@ public function testNotClassPropertyException($identifier) * * @see testNotClassPropertyException() * - * @return array + * @return array> */ - public function dataNotClassProperty() + public static function dataNotClassProperty() { return [ - ['/* testMethodParam */'], - ['/* testImportedGlobal */'], - ['/* testLocalVariable */'], - ['/* testGlobalVariable */'], - ['/* testNestedMethodParam 1 */'], - ['/* testNestedMethodParam 2 */'], - ['/* testEnumMethodParamNotProperty */'], + 'method parameter' => ['/* testMethodParam */'], + 'variable import using global keyword' => ['/* testImportedGlobal */'], + 'function local variable' => ['/* testLocalVariable */'], + 'global variable' => ['/* testGlobalVariable */'], + 'method parameter in anon class nested in ternary' => ['/* testNestedMethodParam 1 */'], + 'method parameter in anon class nested in function call' => ['/* testNestedMethodParam 2 */'], + 'method parameter in enum' => ['/* testEnumMethodParamNotProperty */'], ]; }//end dataNotClassProperty() @@ -848,15 +1383,14 @@ public function dataNotClassProperty() /** * Test receiving an expected exception when a non variable is passed. * - * @expectedException PHP_CodeSniffer\Exceptions\RuntimeException - * @expectedExceptionMessage $stackPtr must be of type T_VARIABLE - * * @return void */ public function testNotAVariableException() { - $next = $this->getTargetToken('/* testNotAVariable */', T_RETURN); - $result = self::$phpcsFile->getMemberProperties($next); + $this->expectRunTimeException('$stackPtr must be of type T_VARIABLE'); + + $next = $this->getTargetToken('/* testNotAVariable */', T_RETURN); + self::$phpcsFile->getMemberProperties($next); }//end testNotAVariableException() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc new file mode 100644 index 000000000..465679eb3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersParseError1Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an empty array when encountering a specific parse error. + * + * @return void + */ + public function testParseError() + { + $target = $this->getTargetToken('/* testParseError */', [T_FUNCTION, T_CLOSURE, T_FN]); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testParseError() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc new file mode 100644 index 000000000..667cb5ed2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersParseError2Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an empty array when encountering a specific parse error. + * + * @return void + */ + public function testParseError() + { + $target = $this->getTargetToken('/* testParseError */', [T_FUNCTION, T_CLOSURE, T_FN]); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testParseError() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc index dc4654914..a4d8767ef 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc @@ -1,5 +1,29 @@ $b; +/* testArrowFunctionReturnByRef */ +fn&(?string $a) => $b; + +/* testArrayDefaultValues */ +function arrayDefaultValues($var1 = [], $var2 = array(1, 2, 3) ) {} + +/* testConstantDefaultValueSecondParam */ +function constantDefaultValueSecondParam($var1, $var2 = M_PI) {} + +/* testScalarTernaryExpressionInDefault */ +function ternayInDefault( $a = FOO ? 'bar' : 10, ? bool $b ) {} + +/* testVariadicFunction */ +function variadicFunction( int ... $a ) {} + +/* testVariadicByRefFunction */ +function variadicByRefFunction( &...$a ) {} + +/* testVariadicFunctionClassType */ +function variableLengthArgument($unit, DateInterval ...$intervals) {} + +/* testNameSpacedTypeDeclaration */ +function namespacedClassType( \Package\Sub\ClassName $a, ?Sub\AnotherClass $b ) {} + +/* testWithAllTypes */ +class testAllTypes { + function allTypes( + ?ClassName $a, + self $b, + parent $c, + object $d, + ?int $e, + string &$f, + iterable $g, + bool $h = true, + callable $i = 'is_null', + float $j = 1.1, + array ...$k + ) {} +} + +/* testArrowFunctionWithAllTypes */ +$fn = fn( + ?ClassName $a, + self $b, + parent $c, + object $d, + ?int $e, + string &$f, + iterable $g, + bool $h = true, + callable $i = 'is_null', + float $j = 1.1, + array ...$k +) => $something; + +/* testMessyDeclaration */ +function messyDeclaration( + // comment + ?\MyNS /* comment */ + \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. + \ MyClass $a, + $b /* comment */ = /* comment */ 'default' /* comment*/, + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + ? /*comment*/ + bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. + & /*test*/ ... /* phpcs:ignore */ $c +) {} + /* testPHP8MixedTypeHint */ function mixedTypeHint(mixed &...$var1) {} @@ -46,7 +139,7 @@ function namespaceOperatorTypeHint(?namespace\Name $var1) {} function unionTypeSimple(int|float $number, self|parent &...$obj) {} /* testPHP8UnionTypesWithSpreadOperatorAndReference */ -function globalFunctionWithSpreadAndReference(float|null &$paramA, string|int ...$paramB) {} +function globalFunctionWithSpreadAndReference(float|null &$paramA, string|int ...$paramB ) {} /* testPHP8UnionTypesSimpleWithBitwiseOrInDefault */ $fn = fn(int|float $var = CONSTANT_A | CONSTANT_B) => $var; @@ -66,11 +159,11 @@ function unionTypesAllPseudoTypes(false|mixed|self|parent|iterable|Resource $var $closure = function (?int|float $number) {}; /* testPHP8PseudoTypeNull */ -// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeNull(null $var = null) {} /* testPHP8PseudoTypeFalse */ -// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeFalse(false $var = false) {} /* testPHP8PseudoTypeFalseAndBool */ @@ -110,7 +203,18 @@ class ConstructorPropertyPromotionAndNormalParams { class ConstructorPropertyPromotionWithReadOnly { /* testPHP81ConstructorPropertyPromotionWithReadOnly */ - public function __construct(public readonly ?int $promotedProp, readonly private string|bool &$promotedToo) {} + public function __construct(public readonly ?int $promotedProp, ReadOnly private string|bool &$promotedToo) {} +} + +class ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration { + /* testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration */ + // Intentional fatal error. Readonly properties MUST be typed. + public function __construct(public readonly $promotedProp, ReadOnly private &$promotedToo) {} +} + +class ConstructorPropertyPromotionWithOnlyReadOnly { + /* testPHP81ConstructorPropertyPromotionWithOnlyReadOnly */ + public function __construct(readonly Foo&Bar $promotedProp, readonly ?bool $promotedToo,) {} } /* testPHP8ConstructorPropertyPromotionGlobalFunction */ @@ -162,3 +266,76 @@ $closure = function (string&int $numeric_string) {}; /* testPHP81NullableIntersectionTypes */ // Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. $closure = function (?Foo&Bar $object) {}; + +/* testPHP82PseudoTypeTrue */ +function pseudoTypeTrue(?true $var = true) {} + +/* testPHP82PseudoTypeFalseAndTrue */ +// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. +function pseudoTypeFalseAndTrue(true|false $var = true) {} + +/* testPHP81NewInInitializers */ +function newInInitializers( + TypeA $new = new TypeA(self::CONST_VALUE), + \Package\TypeB $newToo = new \Package\TypeB(10, 'string'), +) {} + +/* testPHP82DNFTypes */ +function dnfTypes( + #[MyAttribute] + false|(Foo&Bar)|true $obj1, + (\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo() +) {} + +/* testPHP82DNFTypesWithSpreadOperatorAndReference */ +function dnfInGlobalFunctionWithSpreadAndReference((Countable&MeMe)|iterable &$paramA, true|(Foo&Bar) ...$paramB) {} + +/* testPHP82DNFTypesIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +$dnf_closure = function (? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var): void {}; + +/* testPHP82DNFTypesInArrow */ +$dnf_arrow = fn((Hi&Ho)|FALSE &...$range): string => $a; + +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + +/* testClosureNoParams */ +function() {}; + +/* testClosure */ +function( $a = 'test' ) {}; + +/* testClosureUseNoParams */ +function() use() {}; + +/* testClosureUse */ +function() use( $foo, $bar ) {}; + +/* testClosureUseWithReference */ +$cl = function() use (&$foo, &$bar) {}; + +/* testFunctionParamListWithTrailingComma */ +function trailingComma( + ?string $foo /*comment*/ , + $bar = 0, +) {} + +/* testClosureParamListWithTrailingComma */ +function( + $foo, + $bar, +) {}; + +/* testArrowFunctionParamListWithTrailingComma */ +$fn = fn( ?int $a , ...$b, ) => $b; + +/* testClosureUseWithTrailingComma */ +function() use( + $foo /*comment*/ , + $bar, +) {}; + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php index ba4d75448..8d0472097 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php @@ -1,20 +1,163 @@ + * @author Juliette Reinders Folmer * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class GetMethodParametersTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersTest extends AbstractMethodUnitTest { + /** + * Test receiving an expected exception when a non function/use token is passed. + * + * @param string $commentString The comment which preceeds the test. + * @param int|string|array $targetTokenType The token type to search for after $commentString. + * + * @dataProvider dataUnexpectedTokenException + * + * @return void + */ + public function testUnexpectedTokenException($commentString, $targetTokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); + + $target = $this->getTargetToken($commentString, $targetTokenType); + self::$phpcsFile->getMethodParameters($target); + + }//end testUnexpectedTokenException() + + + /** + * Data Provider. + * + * @see testUnexpectedTokenException() For the array format. + * + * @return array>> + */ + public static function dataUnexpectedTokenException() + { + return [ + 'interface' => [ + 'commentString' => '/* testNotAFunction */', + 'targetTokenType' => T_INTERFACE, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + 'commentString' => '/* testFunctionCallFnPHPCS353-354 */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + 'fn-live-coding' => [ + 'commentString' => '/* testArrowFunctionLiveCoding */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + ]; + + }//end dataUnexpectedTokenException() + + + /** + * Test receiving an expected exception when a non-closure use token is passed. + * + * @param string $identifier The comment which preceeds the test. + * + * @dataProvider dataInvalidUse + * + * @return void + */ + public function testInvalidUse($identifier) + { + $this->expectRunTimeException('$stackPtr was not a valid T_USE'); + + $use = $this->getTargetToken($identifier, [T_USE]); + self::$phpcsFile->getMethodParameters($use); + + }//end testInvalidUse() + + + /** + * Data Provider. + * + * @see testInvalidUse() For the array format. + * + * @return array> + */ + public static function dataInvalidUse() + { + return [ + 'ImportUse' => ['/* testImportUse */'], + 'ImportGroupUse' => ['/* testImportGroupUse */'], + 'TraitUse' => ['/* testTraitUse */'], + ]; + + }//end dataInvalidUse() + + + /** + * Test receiving an empty array when there are no parameters. + * + * @param string $commentString The comment which preceeds the test. + * @param int|string|array $targetTokenType Optional. The token type to search for after $commentString. + * Defaults to the function/closure/arrow tokens. + * + * @dataProvider dataNoParams + * + * @return void + */ + public function testNoParams($commentString, $targetTokenType=[T_FUNCTION, T_CLOSURE, T_FN]) + { + $target = $this->getTargetToken($commentString, $targetTokenType); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testNoParams() + + + /** + * Data Provider. + * + * @see testNoParams() For the array format. + * + * @return array>> + */ + public static function dataNoParams() + { + return [ + 'FunctionNoParams' => [ + 'commentString' => '/* testFunctionNoParams */', + ], + 'ClosureNoParams' => [ + 'commentString' => '/* testClosureNoParams */', + ], + 'ClosureUseNoParams' => [ + 'commentString' => '/* testClosureUseNoParams */', + 'targetTokenType' => T_USE, + ], + ]; + + }//end dataNoParams() + + /** * Verify pass-by-reference parsing. * @@ -22,15 +165,22 @@ class GetMethodParametersTest extends AbstractMethodUnitTest */ public function testPassByReference() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => '&$var', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 5, + 'name' => '$var', + 'content' => '&$var', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 4, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -45,15 +195,22 @@ public function testPassByReference() */ public function testArrayHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'array $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'array', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$var', + 'content' => 'array $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -68,15 +225,22 @@ public function testArrayHint() */ public function testVariable() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => '$var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var', + 'content' => '$var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -91,16 +255,25 @@ public function testVariable() */ public function testSingleDefaultValue() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '$var1=self::CONSTANT', - 'has_attributes' => false, - 'default' => 'self::CONSTANT', - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1=self::CONSTANT', + 'default' => 'self::CONSTANT', + 'default_token' => 6, + 'default_equal_token' => 5, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -115,26 +288,43 @@ public function testSingleDefaultValue() */ public function testDefaultValues() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '$var1=1', - 'has_attributes' => false, - 'default' => '1', - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1=1', + 'default' => '1', + 'default_token' => 6, + 'default_equal_token' => 5, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 7, ]; $expected[1] = [ - 'name' => '$var2', - 'content' => "\$var2='value'", - 'has_attributes' => false, - 'default' => "'value'", - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 9, + 'name' => '$var2', + 'content' => "\$var2='value'", + 'default' => "'value'", + 'default_token' => 11, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -149,25 +339,38 @@ public function testDefaultValues() */ public function testTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => 'foo $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'foo', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$var1', + 'content' => 'foo $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'foo', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => 7, ]; $expected[1] = [ - 'name' => '$var2', - 'content' => 'bar $var2', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'bar', - 'nullable_type' => false, + 'token' => 11, + 'name' => '$var2', + 'content' => 'bar $var2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bar', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -182,15 +385,22 @@ public function testTypeHint() */ public function testSelfTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'self $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'self', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$var', + 'content' => 'self $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -205,25 +415,38 @@ public function testSelfTypeHint() */ public function testNullableTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '?int $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int', - 'nullable_type' => true, + 'token' => 7, + 'name' => '$var1', + 'content' => '?int $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => 8, ]; $expected[1] = [ - 'name' => '$var2', - 'content' => '?\bar $var2', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?\bar', - 'nullable_type' => true, + 'token' => 14, + 'name' => '$var2', + 'content' => '?\bar $var2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?\bar', + 'type_hint_token' => 11, + 'type_hint_end_token' => 12, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -238,16 +461,25 @@ public function testNullableTypeHint() */ public function testBitwiseAndConstantExpressionDefaultValue() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$a', - 'content' => '$a = 10 & 20', - 'default' => '10 & 20', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$a', + 'content' => '$a = 10 & 20', + 'default' => '10 & 20', + 'default_token' => 8, + 'default_equal_token' => 6, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -262,25 +494,38 @@ public function testBitwiseAndConstantExpressionDefaultValue() */ public function testArrowFunction() { + // Offsets are relative to the T_FN token. $expected = []; $expected[0] = [ - 'name' => '$a', - 'content' => 'int $a', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$a', + 'content' => 'int $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 2, + 'type_hint_end_token' => 2, + 'nullable_type' => false, + 'comma_token' => 5, ]; $expected[1] = [ - 'name' => '$b', - 'content' => '...$b', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => true, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 8, + 'name' => '$b', + 'content' => '...$b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -289,855 +534,2692 @@ public function testArrowFunction() /** - * Verify recognition of PHP8 mixed type declaration. + * Verify that arrow functions are supported. * * @return void */ - public function testPHP8MixedTypeHint() + public function testArrowFunctionReturnByRef() { + // Offsets are relative to the T_FN token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => 'mixed &...$var1', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => 'mixed', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$a', + 'content' => '?string $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8MixedTypeHint() + }//end testArrowFunctionReturnByRef() /** - * Verify recognition of PHP8 mixed type declaration with nullability. + * Verify default value parsing with array values. * * @return void */ - public function testPHP8MixedTypeHintNullable() + public function testArrayDefaultValues() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '?Mixed $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?Mixed', - 'nullable_type' => true, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1 = []', + 'default' => '[]', + 'default_token' => 8, + 'default_equal_token' => 6, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 10, ]; - - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - - }//end testPHP8MixedTypeHintNullable() - - - /** - * Verify recognition of type declarations using the namespace operator. - * - * @return void - */ - public function testNamespaceOperatorTypeHint() - { - $expected = []; - $expected[0] = [ - 'name' => '$var1', - 'content' => '?namespace\Name $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?namespace\Name', - 'nullable_type' => true, + $expected[1] = [ + 'token' => 12, + 'name' => '$var2', + 'content' => '$var2 = array(1, 2, 3)', + 'default' => 'array(1, 2, 3)', + 'default_token' => 16, + 'default_equal_token' => 14, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testNamespaceOperatorTypeHint() + }//end testArrayDefaultValues() /** - * Verify recognition of PHP8 union type declaration. + * Verify having a T_STRING constant as a default value for the second parameter. * * @return void */ - public function testPHP8UnionTypesSimple() + public function testConstantDefaultValueSecondParam() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$number', - 'content' => 'int|float $number', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int|float', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, ]; $expected[1] = [ - 'name' => '$obj', - 'content' => 'self|parent &...$obj', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => 'self|parent', - 'nullable_type' => false, + 'token' => 7, + 'name' => '$var2', + 'content' => '$var2 = M_PI', + 'default' => 'M_PI', + 'default_token' => 11, + 'default_equal_token' => 9, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesSimple() + }//end testConstantDefaultValueSecondParam() /** - * Verify recognition of PHP8 union type declaration when the variable has either a spread operator or a reference. + * Verify distinquishing between a nullable type and a ternary within a default expression. * * @return void */ - public function testPHP8UnionTypesWithSpreadOperatorAndReference() + public function testScalarTernaryExpressionInDefault() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$paramA', - 'content' => 'float|null &$paramA', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => 'float|null', - 'nullable_type' => false, + 'token' => 5, + 'name' => '$a', + 'content' => '$a = FOO ? \'bar\' : 10', + 'default' => 'FOO ? \'bar\' : 10', + 'default_token' => 9, + 'default_equal_token' => 7, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 18, ]; $expected[1] = [ - 'name' => '$paramB', - 'content' => 'string|int ...$paramB', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => true, - 'type_hint' => 'string|int', - 'nullable_type' => false, + 'token' => 24, + 'name' => '$b', + 'content' => '? bool $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?bool', + 'type_hint_token' => 22, + 'type_hint_end_token' => 22, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesWithSpreadOperatorAndReference() + }//end testScalarTernaryExpressionInDefault() /** - * Verify recognition of PHP8 union type declaration with a bitwise or in the default value. + * Verify a variadic parameter being recognized correctly. * * @return void */ - public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + public function testVariadicFunction() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', - 'default' => 'CONSTANT_A | CONSTANT_B', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int|float', - 'nullable_type' => false, + 'token' => 9, + 'name' => '$a', + 'content' => 'int ... $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => 'int', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + }//end testVariadicFunction() /** - * Verify recognition of PHP8 union type declaration with two classes. + * Verify a variadic parameter passed by reference being recognized correctly. * * @return void */ - public function testPHP8UnionTypesTwoClasses() + public function testVariadicByRefFunction() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'MyClassA|\Package\MyClassB $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'MyClassA|\Package\MyClassB', - 'nullable_type' => false, + 'token' => 7, + 'name' => '$a', + 'content' => '&...$a', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 5, + 'variable_length' => true, + 'variadic_token' => 6, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesTwoClasses() + }//end testVariadicByRefFunction() /** - * Verify recognition of PHP8 union type declaration with all base types. + * Verify handling of a variadic parameter with a class based type declaration. * * @return void */ - public function testPHP8UnionTypesAllBaseTypes() + public function testVariadicFunctionClassType() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'array|bool|callable|int|float|null|object|string $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'array|bool|callable|int|float|null|object|string', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$unit', + 'content' => '$unit', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, ]; - - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - - }//end testPHP8UnionTypesAllBaseTypes() - - - /** - * Verify recognition of PHP8 union type declaration with all pseudo types. - * - * @return void - */ - public function testPHP8UnionTypesAllPseudoTypes() - { - $expected = []; - $expected[0] = [ - 'name' => '$var', - 'content' => 'false|mixed|self|parent|iterable|Resource $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'false|mixed|self|parent|iterable|Resource', - 'nullable_type' => false, + $expected[1] = [ + 'token' => 10, + 'name' => '$intervals', + 'content' => 'DateInterval ...$intervals', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 9, + 'type_hint' => 'DateInterval', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesAllPseudoTypes() + }//end testVariadicFunctionClassType() /** - * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * Verify distinquishing between a nullable type and a ternary within a default expression. * * @return void */ - public function testPHP8UnionTypesNullable() + public function testNameSpacedTypeDeclaration() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$number', - 'content' => '?int|float $number', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int|float', - 'nullable_type' => true, + 'token' => 12, + 'name' => '$a', + 'content' => '\Package\Sub\ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '\Package\Sub\ClassName', + 'type_hint_token' => 5, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 20, + 'name' => '$b', + 'content' => '?Sub\AnotherClass $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Sub\AnotherClass', + 'type_hint_token' => 16, + 'type_hint_end_token' => 18, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesNullable() + }//end testNameSpacedTypeDeclaration() /** - * Verify recognition of PHP8 type declaration with (illegal) single type null. + * Verify correctly recognizing all type declarations supported by PHP. * * @return void */ - public function testPHP8PseudoTypeNull() + public function testWithAllTypes() { - $expected = []; - $expected[0] = [ - 'name' => '$var', - 'content' => 'null $var = null', - 'default' => 'null', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'null', - 'nullable_type' => false, + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$a', + 'content' => '?ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?ClassName', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 15, + 'name' => '$b', + 'content' => 'self $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 13, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => 16, + ]; + $expected[2] = [ + 'token' => 21, + 'name' => '$c', + 'content' => 'parent $c', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'parent', + 'type_hint_token' => 19, + 'type_hint_end_token' => 19, + 'nullable_type' => false, + 'comma_token' => 22, + ]; + $expected[3] = [ + 'token' => 27, + 'name' => '$d', + 'content' => 'object $d', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object', + 'type_hint_token' => 25, + 'type_hint_end_token' => 25, + 'nullable_type' => false, + 'comma_token' => 28, + ]; + $expected[4] = [ + 'token' => 34, + 'name' => '$e', + 'content' => '?int $e', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 32, + 'type_hint_end_token' => 32, + 'nullable_type' => true, + 'comma_token' => 35, + ]; + $expected[5] = [ + 'token' => 41, + 'name' => '$f', + 'content' => 'string &$f', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 40, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 38, + 'type_hint_end_token' => 38, + 'nullable_type' => false, + 'comma_token' => 42, + ]; + $expected[6] = [ + 'token' => 47, + 'name' => '$g', + 'content' => 'iterable $g', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable', + 'type_hint_token' => 45, + 'type_hint_end_token' => 45, + 'nullable_type' => false, + 'comma_token' => 48, + ]; + $expected[7] = [ + 'token' => 53, + 'name' => '$h', + 'content' => 'bool $h = true', + 'default' => 'true', + 'default_token' => 57, + 'default_equal_token' => 55, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool', + 'type_hint_token' => 51, + 'type_hint_end_token' => 51, + 'nullable_type' => false, + 'comma_token' => 58, + ]; + $expected[8] = [ + 'token' => 63, + 'name' => '$i', + 'content' => 'callable $i = \'is_null\'', + 'default' => "'is_null'", + 'default_token' => 67, + 'default_equal_token' => 65, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 61, + 'type_hint_end_token' => 61, + 'nullable_type' => false, + 'comma_token' => 68, + ]; + $expected[9] = [ + 'token' => 73, + 'name' => '$j', + 'content' => 'float $j = 1.1', + 'default' => '1.1', + 'default_token' => 77, + 'default_equal_token' => 75, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float', + 'type_hint_token' => 71, + 'type_hint_end_token' => 71, + 'nullable_type' => false, + 'comma_token' => 78, + ]; + $expected[10] = [ + 'token' => 84, + 'name' => '$k', + 'content' => 'array ...$k', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 83, + 'type_hint' => 'array', + 'type_hint_token' => 81, + 'type_hint_end_token' => 81, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testWithAllTypes() + + + /** + * Verify correctly recognizing all type declarations supported by PHP when used with an arrow function. + * + * @return void + */ + public function testArrowFunctionWithAllTypes() + { + // Offsets are relative to the T_FN token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$a', + 'content' => '?ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?ClassName', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 13, + 'name' => '$b', + 'content' => 'self $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 11, + 'type_hint_end_token' => 11, + 'nullable_type' => false, + 'comma_token' => 14, + ]; + $expected[2] = [ + 'token' => 19, + 'name' => '$c', + 'content' => 'parent $c', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'parent', + 'type_hint_token' => 17, + 'type_hint_end_token' => 17, + 'nullable_type' => false, + 'comma_token' => 20, + ]; + $expected[3] = [ + 'token' => 25, + 'name' => '$d', + 'content' => 'object $d', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object', + 'type_hint_token' => 23, + 'type_hint_end_token' => 23, + 'nullable_type' => false, + 'comma_token' => 26, + ]; + $expected[4] = [ + 'token' => 32, + 'name' => '$e', + 'content' => '?int $e', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 30, + 'type_hint_end_token' => 30, + 'nullable_type' => true, + 'comma_token' => 33, + ]; + $expected[5] = [ + 'token' => 39, + 'name' => '$f', + 'content' => 'string &$f', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 38, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 36, + 'type_hint_end_token' => 36, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[6] = [ + 'token' => 45, + 'name' => '$g', + 'content' => 'iterable $g', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable', + 'type_hint_token' => 43, + 'type_hint_end_token' => 43, + 'nullable_type' => false, + 'comma_token' => 46, + ]; + $expected[7] = [ + 'token' => 51, + 'name' => '$h', + 'content' => 'bool $h = true', + 'default' => 'true', + 'default_token' => 55, + 'default_equal_token' => 53, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool', + 'type_hint_token' => 49, + 'type_hint_end_token' => 49, + 'nullable_type' => false, + 'comma_token' => 56, + ]; + $expected[8] = [ + 'token' => 61, + 'name' => '$i', + 'content' => 'callable $i = \'is_null\'', + 'default' => "'is_null'", + 'default_token' => 65, + 'default_equal_token' => 63, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 59, + 'type_hint_end_token' => 59, + 'nullable_type' => false, + 'comma_token' => 66, + ]; + $expected[9] = [ + 'token' => 71, + 'name' => '$j', + 'content' => 'float $j = 1.1', + 'default' => '1.1', + 'default_token' => 75, + 'default_equal_token' => 73, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float', + 'type_hint_token' => 69, + 'type_hint_end_token' => 69, + 'nullable_type' => false, + 'comma_token' => 76, + ]; + $expected[10] = [ + 'token' => 82, + 'name' => '$k', + 'content' => 'array ...$k', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 81, + 'type_hint' => 'array', + 'type_hint_token' => 79, + 'type_hint_end_token' => 79, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionWithAllTypes() + + + /** + * Verify handling of a declaration interlaced with whitespace and comments. + * + * @return void + */ + public function testMessyDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 25, + 'name' => '$a', + 'content' => '// comment + ?\MyNS /* comment */ + \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. + \ MyClass $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?\MyNS\SubCat\MyClass', + 'type_hint_token' => 9, + 'type_hint_end_token' => 23, + 'nullable_type' => true, + 'comma_token' => 26, + ]; + $expected[1] = [ + 'token' => 29, + 'name' => '$b', + 'content' => "\$b /* comment */ = /* comment */ 'default' /* comment*/", + 'default' => "'default' /* comment*/", + 'default_token' => 37, + 'default_equal_token' => 33, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[2] = [ + 'token' => 62, + 'name' => '$c', + 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- For reasons. + ? /*comment*/ + bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. + & /*test*/ ... /* phpcs:ignore */ $c', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 54, + 'variable_length' => true, + 'variadic_token' => 58, + 'type_hint' => '?bool', + 'type_hint_token' => 50, + 'type_hint_end_token' => 50, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testMessyDeclaration() + + + /** + * Verify recognition of PHP8 mixed type declaration. + * + * @return void + */ + public function testPHP8MixedTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var1', + 'content' => 'mixed &...$var1', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 6, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => 'mixed', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHint() + + + /** + * Verify recognition of PHP8 mixed type declaration with nullability. + * + * @return void + */ + public function testPHP8MixedTypeHintNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$var1', + 'content' => '?Mixed $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Mixed', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHintNullable() + + + /** + * Verify recognition of type declarations using the namespace operator. + * + * @return void + */ + public function testNamespaceOperatorTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$var1', + 'content' => '?namespace\Name $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?namespace\Name', + 'type_hint_token' => 5, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNamespaceOperatorTypeHint() + + + /** + * Verify recognition of PHP8 union type declaration. + * + * @return void + */ + public function testPHP8UnionTypesSimple() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$number', + 'content' => 'int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$obj', + 'content' => 'self|parent &...$obj', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'self|parent', + 'type_hint_token' => 11, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesSimple() + + + /** + * Verify recognition of PHP8 union type declaration when the variable has either a spread operator or a reference. + * + * @return void + */ + public function testPHP8UnionTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$paramA', + 'content' => 'float|null &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|null', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$paramB', + 'content' => 'string|int ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'string|int', + 'type_hint_token' => 12, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP8 union type declaration with a bitwise or in the default value. + * + * @return void + */ + public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', + 'default' => 'CONSTANT_A | CONSTANT_B', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 2, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 11, + 'name' => '$var', + 'content' => 'MyClassA|\Package\MyClassB $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA|\Package\MyClassB', + 'type_hint_token' => 4, + 'type_hint_end_token' => 9, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesTwoClasses() + + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 20, + 'name' => '$var', + 'content' => 'array|bool|callable|int|float|null|object|string $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array|bool|callable|int|float|null|object|string', + 'type_hint_token' => 4, + 'type_hint_end_token' => 18, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllBaseTypes() + + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 16, + 'name' => '$var', + 'content' => 'false|mixed|self|parent|iterable|Resource $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|mixed|self|parent|iterable|Resource', + 'type_hint_token' => 4, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllPseudoTypes() + + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$number', + 'content' => '?int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int|float', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesNullable() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'null $var = null', + 'default' => 'null', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'null', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeNull() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'false $var = false', + 'default' => 'false', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalse() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'bool|false $var = false', + 'default' => 'false', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool|false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalseAndBool() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'object|ClassName $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object|ClassName', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ObjectAndClass() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$var', + 'content' => 'iterable|array|Traversable $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable|array|Traversable', + 'type_hint_token' => 4, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeIterableAndArray() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 17, + 'name' => '$var', + 'content' => 'int | string /*comment*/ | INT $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|string|INT', + 'type_hint_token' => 5, + 'type_hint_end_token' => 15, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8DuplicateTypeInUnionWhitespaceAndComment() + + + /** + * Verify recognition of PHP8 constructor property promotion without type declaration, with defaults. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionNoTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$x', + 'content' => 'public $x = 0.0', + 'default' => '0.0', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 6, + 'property_readonly' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 18, + 'name' => '$y', + 'content' => 'protected $y = \'\'', + 'default' => "''", + 'default_token' => 22, + 'default_equal_token' => 20, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 16, + 'property_readonly' => false, + 'comma_token' => 23, + ]; + $expected[2] = [ + 'token' => 28, + 'name' => '$z', + 'content' => 'private $z = null', + 'default' => 'null', + 'default_token' => 32, + 'default_equal_token' => 30, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, + 'property_readonly' => false, + 'comma_token' => 33, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionNoTypes() + + + /** + * Verify recognition of PHP8 constructor property promotion with type declarations. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionWithTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$x', + 'content' => 'protected float|int $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|int', + 'type_hint_token' => 6, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 11, + ]; + $expected[1] = [ + 'token' => 19, + 'name' => '$y', + 'content' => 'public ?string &$y = \'test\'', + 'default' => "'test'", + 'default_token' => 23, + 'default_equal_token' => 21, + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 18, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 16, + 'type_hint_end_token' => 16, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 13, + 'property_readonly' => false, + 'comma_token' => 24, + ]; + $expected[2] = [ + 'token' => 30, + 'name' => '$z', + 'content' => 'private mixed $z', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'mixed', + 'type_hint_token' => 28, + 'type_hint_end_token' => 28, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionWithTypes() + + + /** + * Verify recognition of PHP8 constructor with both property promotion as well as normal parameters. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionAndNormalParam() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$promotedProp', + 'content' => 'public int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, + 'name' => '$normalArg', + 'content' => '?int $normalArg', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 12, + 'type_hint_end_token' => 12, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionAndNormalParam() + + + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword. + * + * @return void + */ + public function testPHP81ConstructorPropertyPromotionWithReadOnly() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 11, + 'name' => '$promotedProp', + 'content' => 'public readonly ?int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => true, + 'readonly_token' => 6, + 'comma_token' => 12, + ]; + $expected[1] = [ + 'token' => 23, + 'name' => '$promotedToo', + 'content' => 'ReadOnly private string|bool &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 22, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string|bool', + 'type_hint_token' => 18, + 'type_hint_end_token' => 20, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 16, + 'property_readonly' => true, + 'readonly_token' => 14, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81ConstructorPropertyPromotionWithReadOnly() + + + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword + * without a property type. + * + * @return void + */ + public function testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$promotedProp', + 'content' => 'public readonly $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => true, + 'readonly_token' => 6, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 16, + 'name' => '$promotedToo', + 'content' => 'ReadOnly private &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 13, + 'property_readonly' => true, + 'readonly_token' => 11, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeNull() + }//end testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration() /** - * Verify recognition of PHP8 type declaration with (illegal) single type false. + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly + * keyword without explicit visibility. * * @return void */ - public function testPHP8PseudoTypeFalse() + public function testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'false $var = false', - 'default' => 'false', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'false', - 'nullable_type' => false, + 'token' => 10, + 'name' => '$promotedProp', + 'content' => 'readonly Foo&Bar $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 6, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'property_readonly' => true, + 'readonly_token' => 4, + 'comma_token' => 11, + ]; + $expected[1] = [ + 'token' => 18, + 'name' => '$promotedToo', + 'content' => 'readonly ?bool $promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?bool', + 'type_hint_token' => 16, + 'type_hint_end_token' => 16, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'property_readonly' => true, + 'readonly_token' => 13, + 'comma_token' => 19, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeFalse() + }//end testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() /** - * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. * * @return void */ - public function testPHP8PseudoTypeFalseAndBool() + public function testPHP8ConstructorPropertyPromotionGlobalFunction() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$x', + 'content' => 'private $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionGlobalFunction() + + + /** + * Verify behaviour when an abstract constructor uses PHP 8 property promotion syntax. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionAbstractMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$y', + 'content' => 'public callable $y', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, + 'name' => '$x', + 'content' => 'private ...$x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 13, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 11, + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionAbstractMethod() + + + /** + * Verify and document behaviour when there are comments within a parameter declaration. + * + * @return void + */ + public function testCommentsInParameter() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 19, + 'name' => '$param', + 'content' => '// Leading comment. + ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ \'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default' => '\'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default_token' => 27, + 'default_equal_token' => 23, + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 13, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => '?MyClass', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testCommentsInParameter() + + + /** + * Verify behaviour when parameters have attributes attached. + * + * @return void + */ + public function testParameterAttributesInFunctionDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 17, + 'name' => '$constructorPropPromTypedParamSingleAttribute', + 'content' => '#[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 15, + 'type_hint_end_token' => 15, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 13, + 'property_readonly' => false, + 'comma_token' => 18, + ]; + $expected[1] = [ + 'token' => 39, + 'name' => '$typedParamSingleAttribute', + 'content' => '#[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Type|false', + 'type_hint_token' => 34, + 'type_hint_end_token' => 36, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[2] = [ + 'token' => 59, + 'name' => '$nullableTypedParamMultiAttribute', + 'content' => '#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 57, + 'type_hint_end_token' => 57, + 'nullable_type' => true, + 'comma_token' => 60, + ]; + $expected[3] = [ + 'token' => 74, + 'name' => '$nonTypedParamTwoAttributes', + 'content' => '#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 75, + ]; + $expected[4] = [ + 'token' => 95, + 'name' => '$otherParam', + 'content' => '#[MyAttribute(array("key" => "value"))] + &...$otherParam', + 'has_attributes' => true, + 'pass_by_reference' => true, + 'reference_token' => 93, + 'variable_length' => true, + 'variadic_token' => 94, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 96, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testParameterAttributesInFunctionDeclaration() + + + /** + * Verify recognition of PHP8.1 intersection type declaration. + * + * @return void + */ + public function testPHP8IntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$obj1', + 'content' => 'Foo&Bar $obj1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 15, + 'name' => '$obj2', + 'content' => 'Boo&Bar $obj2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 11, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8IntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration when the variable + * has either a spread operator or a reference. + * + * @return void + */ + public function testPHP81IntersectionTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$paramA', + 'content' => 'Boo&Bar &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$paramB', + 'content' => 'Foo&Bar ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 12, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81IntersectionTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with more types. + * + * @return void + */ + public function testPHP81MoreIntersectionTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 16, + 'name' => '$var', + 'content' => 'MyClassA&\Package\MyClassB&\Package\MyClassC $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'type_hint_token' => 4, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81MoreIntersectionTypes() + + + /** + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * + * @return void + */ + public function testPHP81IllegalIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'bool|false $var = false', - 'default' => 'false', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'bool|false', - 'nullable_type' => false, + 'token' => 7, + 'name' => '$numeric_string', + 'content' => 'string&int $numeric_string', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string&int', + 'type_hint_token' => 3, + 'type_hint_end_token' => 5, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeFalseAndBool() + }//end testPHP81IllegalIntersectionTypes() /** - * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. * * @return void */ - public function testPHP8ObjectAndClass() + public function testPHP81NullableIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'object|ClassName $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'object|ClassName', - 'nullable_type' => false, + 'token' => 8, + 'name' => '$object', + 'content' => '?Foo&Bar $object', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Foo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ObjectAndClass() + }//end testPHP81NullableIntersectionTypes() /** - * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * Verify recognition of PHP 8.2 stand-alone `true` type. * * @return void */ - public function testPHP8PseudoTypeIterableAndArray() + public function testPHP82PseudoTypeTrue() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'iterable|array|Traversable $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'iterable|array|Traversable', - 'nullable_type' => false, + 'token' => 7, + 'name' => '$var', + 'content' => '?true $var = true', + 'default' => 'true', + 'default_token' => 11, + 'default_equal_token' => 9, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?true', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeIterableAndArray() + }//end testPHP82PseudoTypeTrue() /** - * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. * * @return void */ - public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + public function testPHP82PseudoTypeFalseAndTrue() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'int | string /*comment*/ | INT $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int|string|INT', - 'nullable_type' => false, + 'token' => 8, + 'name' => '$var', + 'content' => 'true|false $var = true', + 'default' => 'true', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'true|false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8DuplicateTypeInUnionWhitespaceAndComment() + }//end testPHP82PseudoTypeFalseAndTrue() /** - * Verify recognition of PHP8 constructor property promotion without type declaration, with defaults. + * Verify behaviour when the default value uses the "new" keyword, as is allowed per PHP 8.1. * * @return void */ - public function testPHP8ConstructorPropertyPromotionNoTypes() + public function testPHP81NewInInitializers() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$x', - 'content' => 'public $x = 0.0', - 'default' => '0.0', + 'token' => 8, + 'name' => '$new', + 'content' => 'TypeA $new = new TypeA(self::CONST_VALUE)', + 'default' => 'new TypeA(self::CONST_VALUE)', + 'default_token' => 12, + 'default_equal_token' => 10, 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => '', + 'variadic_token' => false, + 'type_hint' => 'TypeA', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, 'nullable_type' => false, - 'property_visibility' => 'public', - 'property_readonly' => false, + 'comma_token' => 20, ]; $expected[1] = [ - 'name' => '$y', - 'content' => 'protected $y = \'\'', - 'default' => "''", - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, - 'property_visibility' => 'protected', - 'property_readonly' => false, - ]; - $expected[2] = [ - 'name' => '$z', - 'content' => 'private $z = null', - 'default' => 'null', + 'token' => 28, + 'name' => '$newToo', + 'content' => '\Package\TypeB $newToo = new \Package\TypeB(10, \'string\')', + 'default' => "new \Package\TypeB(10, 'string')", + 'default_token' => 32, + 'default_equal_token' => 30, 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => '', + 'variadic_token' => false, + 'type_hint' => '\Package\TypeB', + 'type_hint_token' => 23, + 'type_hint_end_token' => 26, 'nullable_type' => false, - 'property_visibility' => 'private', - 'property_readonly' => false, + 'comma_token' => 44, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionNoTypes() + }//end testPHP81NewInInitializers() /** - * Verify recognition of PHP8 constructor property promotion with type declarations. + * Verify recognition of 8.2 DNF parameter type declarations. * * @return void */ - public function testPHP8ConstructorPropertyPromotionWithTypes() + public function testPHP82DNFTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$x', - 'content' => 'protected float|int $x', - 'has_attributes' => false, + 'token' => 21, + 'name' => '$obj1', + 'content' => '#[MyAttribute] + false|(Foo&Bar)|true $obj1', + 'has_attributes' => true, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => 'float|int', + 'variadic_token' => false, + 'type_hint' => 'false|(Foo&Bar)|true', + 'type_hint_token' => 11, + 'type_hint_end_token' => 19, 'nullable_type' => false, - 'property_visibility' => 'protected', - 'property_readonly' => false, + 'comma_token' => 22, ]; $expected[1] = [ - 'name' => '$y', - 'content' => 'public ?string &$y = \'test\'', - 'default' => "'test'", - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => '?string', - 'nullable_type' => true, - 'property_visibility' => 'public', - 'property_readonly' => false, - ]; - $expected[2] = [ - 'name' => '$z', - 'content' => 'private mixed $z', + 'token' => 41, + 'name' => '$obj2', + 'content' => '(\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo()', + 'default' => 'new Boo()', + 'default_token' => 45, + 'default_equal_token' => 43, 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => 'mixed', + 'variadic_token' => false, + 'type_hint' => '(\Boo&\Pck\Bar)|(Boo&Baz)', + 'type_hint_token' => 25, + 'type_hint_end_token' => 39, 'nullable_type' => false, - 'property_visibility' => 'private', - 'property_readonly' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionWithTypes() + }//end testPHP82DNFTypes() /** - * Verify recognition of PHP8 constructor with both property promotion as well as normal parameters. + * Verify recognition of PHP 8.2 DNF parameter type declarations when the variable + * has either a spread operator or a reference. * * @return void */ - public function testPHP8ConstructorPropertyPromotionAndNormalParam() + public function testPHP82DNFTypesWithSpreadOperatorAndReference() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$promotedProp', - 'content' => 'public int $promotedProp', + 'token' => 13, + 'name' => '$paramA', + 'content' => '(Countable&MeMe)|iterable &$paramA', 'has_attributes' => false, - 'pass_by_reference' => false, + 'pass_by_reference' => true, + 'reference_token' => 12, 'variable_length' => false, - 'type_hint' => 'int', + 'variadic_token' => false, + 'type_hint' => '(Countable&MeMe)|iterable', + 'type_hint_token' => 4, + 'type_hint_end_token' => 10, 'nullable_type' => false, - 'property_visibility' => 'public', - 'property_readonly' => false, + 'comma_token' => 14, ]; $expected[1] = [ - 'name' => '$normalArg', - 'content' => '?int $normalArg', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int', - 'nullable_type' => true, + 'token' => 25, + 'name' => '$paramB', + 'content' => 'true|(Foo&Bar) ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 24, + 'type_hint' => 'true|(Foo&Bar)', + 'type_hint_token' => 16, + 'type_hint_end_token' => 22, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionAndNormalParam() + }//end testPHP82DNFTypesWithSpreadOperatorAndReference() /** - * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword. + * Verify recognition of PHP 8.2 DNF parameter type declarations using the nullability operator (not allowed). * * @return void */ - public function testPHP81ConstructorPropertyPromotionWithReadOnly() + public function testPHP82DNFTypesIllegalNullable() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$promotedProp', - 'content' => 'public readonly ?int $promotedProp', + 'token' => 27, + 'name' => '$var', + 'content' => '? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var', 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => '?int', + 'variadic_token' => false, + 'type_hint' => '?(MyClassA&\Package\MyClassB&\Package\MyClassC)', + 'type_hint_token' => 5, + 'type_hint_end_token' => 25, 'nullable_type' => true, - 'property_visibility' => 'public', - 'property_readonly' => true, + 'comma_token' => false, ]; - $expected[1] = [ - 'name' => '$promotedToo', - 'content' => 'readonly private string|bool &$promotedToo', + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations in an arrow function. + * + * @return void + */ + public function testPHP82DNFTypesInArrow() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 12, + 'name' => '$range', + 'content' => '(Hi&Ho)|FALSE &...$range', 'has_attributes' => false, 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => 'string|bool', + 'reference_token' => 10, + 'variable_length' => true, + 'variadic_token' => 11, + 'type_hint' => '(Hi&Ho)|FALSE', + 'type_hint_token' => 2, + 'type_hint_end_token' => 8, 'nullable_type' => false, - 'property_visibility' => 'private', - 'property_readonly' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP81ConstructorPropertyPromotionWithReadOnly() + }//end testPHP82DNFTypesInArrow() /** - * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. + * Verify handling of a closure. * * @return void */ - public function testPHP8ConstructorPropertyPromotionGlobalFunction() + public function testClosure() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$x', - 'content' => 'private $x', + 'token' => 3, + 'name' => '$a', + 'content' => '$a = \'test\'', + 'default' => "'test'", + 'default_token' => 7, + 'default_equal_token' => 5, 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, + 'variadic_token' => false, 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, 'nullable_type' => false, - 'property_visibility' => 'private', + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionGlobalFunction() + }//end testClosure() /** - * Verify behaviour when an abstract constructor uses PHP 8 property promotion syntax. + * Verify handling of a closure T_USE token correctly. * * @return void */ - public function testPHP8ConstructorPropertyPromotionAbstractMethod() + public function testClosureUse() { + // Offsets are relative to the T_USE token. $expected = []; $expected[0] = [ - 'name' => '$y', - 'content' => 'public callable $y', + 'token' => 3, + 'name' => '$foo', + 'content' => '$foo', 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => 'callable', + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, 'nullable_type' => false, - 'property_visibility' => 'public', + 'comma_token' => 4, ]; $expected[1] = [ - 'name' => '$x', - 'content' => 'private ...$x', + 'token' => 6, + 'name' => '$bar', + 'content' => '$bar', 'has_attributes' => false, 'pass_by_reference' => false, - 'variable_length' => true, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, 'nullable_type' => false, - 'property_visibility' => 'private', + 'comma_token' => false, ]; - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); - }//end testPHP8ConstructorPropertyPromotionAbstractMethod() + }//end testClosureUse() /** - * Verify and document behaviour when there are comments within a parameter declaration. + * Verify handling of a closure T_USE token with variables imported by reference. * * @return void */ - public function testCommentsInParameter() + public function testClosureUseWithReference() { + // Offsets are relative to the T_USE token. $expected = []; $expected[0] = [ - 'name' => '$param', - 'content' => '// Leading comment. - ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ \'default value\' . /*-*/ \'second part\' // Trailing comment.', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => '?MyClass', - 'nullable_type' => true, + 'token' => 4, + 'name' => '$foo', + 'content' => '&$foo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 3, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + $expected[1] = [ + 'token' => 8, + 'name' => '$bar', + 'content' => '&$bar', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 7, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); - }//end testCommentsInParameter() + }//end testClosureUseWithReference() /** - * Verify behaviour when parameters have attributes attached. + * Verify function declarations with trailing commas are handled correctly. * * @return void */ - public function testParameterAttributesInFunctionDeclaration() + public function testFunctionParamListWithTrailingComma() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$constructorPropPromTypedParamSingleAttribute', - 'content' => '#[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute', - 'has_attributes' => true, + 'token' => 9, + 'name' => '$foo', + 'content' => '?string $foo /*comment*/', + 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => 'string', - 'nullable_type' => false, - 'property_visibility' => 'private', + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => 13, ]; $expected[1] = [ - 'name' => '$typedParamSingleAttribute', - 'content' => '#[MyAttr([1, 2])] - Type|false - $typedParamSingleAttribute', - 'has_attributes' => true, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'Type|false', - 'nullable_type' => false, - ]; - $expected[2] = [ - 'name' => '$nullableTypedParamMultiAttribute', - 'content' => '#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute', - 'has_attributes' => true, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int', - 'nullable_type' => true, - ]; - $expected[3] = [ - 'name' => '$nonTypedParamTwoAttributes', - 'content' => '#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes', - 'has_attributes' => true, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, - ]; - $expected[4] = [ - 'name' => '$otherParam', - 'content' => '#[MyAttribute(array("key" => "value"))] - &...$otherParam', - 'has_attributes' => true, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 16, + 'name' => '$bar', + 'content' => '$bar = 0', + 'default' => '0', + 'default_token' => 20, + 'default_equal_token' => 18, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 21, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testParameterAttributesInFunctionDeclaration() + }//end testFunctionParamListWithTrailingComma() /** - * Verify recognition of PHP8.1 intersection type declaration. + * Verify closure declarations with trailing commas are handled correctly. * * @return void */ - public function testPHP8IntersectionTypes() + public function testClosureParamListWithTrailingComma() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$obj1', - 'content' => 'Foo&Bar $obj1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'Foo&Bar', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$foo', + 'content' => '$foo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, ]; $expected[1] = [ - 'name' => '$obj2', - 'content' => 'Boo&Bar $obj2', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'Boo&Bar', - 'nullable_type' => false, + 'token' => 8, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 9, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8IntersectionTypes() + }//end testClosureParamListWithTrailingComma() /** - * Verify recognition of PHP8 intersection type declaration when the variable has either a spread operator or a reference. + * Verify arrow function declarations with trailing commas are handled correctly. * * @return void */ - public function testPHP81IntersectionTypesWithSpreadOperatorAndReference() + public function testArrowFunctionParamListWithTrailingComma() { + // Offsets are relative to the T_FN token. $expected = []; $expected[0] = [ - 'name' => '$paramA', - 'content' => 'Boo&Bar &$paramA', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => 'Boo&Bar', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$a', + 'content' => '?int $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => true, + 'comma_token' => 8, ]; $expected[1] = [ - 'name' => '$paramB', - 'content' => 'Foo&Bar ...$paramB', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => true, - 'type_hint' => 'Foo&Bar', - 'nullable_type' => false, + 'token' => 11, + 'name' => '$b', + 'content' => '...$b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 10, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP81IntersectionTypesWithSpreadOperatorAndReference() + }//end testArrowFunctionParamListWithTrailingComma() /** - * Verify recognition of PHP8.1 intersection type declaration with more types. + * Verify closure T_USE statements with trailing commas are handled correctly. * * @return void */ - public function testPHP81MoreIntersectionTypes() + public function testClosureUseWithTrailingComma() { + // Offsets are relative to the T_USE token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'MyClassA&\Package\MyClassB&\Package\MyClassC $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$foo', + 'content' => '$foo /*comment*/', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 11, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, ]; - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); - }//end testPHP81MoreIntersectionTypes() + }//end testClosureUseWithTrailingComma() /** - * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * Test helper. + * + * @param string $commentString The comment which preceeds the test. + * @param array> $expected The expected function output. + * @param int|string|array $targetType Optional. The token type to search for after $marker. + * Defaults to the function/closure/arrow tokens. * * @return void */ - public function testPHP81IllegalIntersectionTypes() + private function getMethodParametersTestHelper($commentString, $expected, $targetType=[T_FUNCTION, T_CLOSURE, T_FN]) { - $expected = []; - $expected[0] = [ - 'name' => '$numeric_string', - 'content' => 'string&int $numeric_string', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'string&int', - 'nullable_type' => false, - ]; + $target = $this->getTargetToken($commentString, $targetType); + $found = self::$phpcsFile->getMethodParameters($target); - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + // Convert offsets to absolute positions in the token stream. + foreach ($expected as $key => $param) { + $expected[$key]['token'] += $target; - }//end testPHP81IllegalIntersectionTypes() + if (is_int($param['reference_token']) === true) { + $expected[$key]['reference_token'] += $target; + } + if (is_int($param['variadic_token']) === true) { + $expected[$key]['variadic_token'] += $target; + } - /** - * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. - * - * @return void - */ - public function testPHP81NullableIntersectionTypes() - { - $expected = []; - $expected[0] = [ - 'name' => '$object', - 'content' => '?Foo&Bar $object', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?Foo&Bar', - 'nullable_type' => true, - ]; + if (is_int($param['type_hint_token']) === true) { + $expected[$key]['type_hint_token'] += $target; + } - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + if (is_int($param['type_hint_end_token']) === true) { + $expected[$key]['type_hint_end_token'] += $target; + } - }//end testPHP81NullableIntersectionTypes() + if (is_int($param['comma_token']) === true) { + $expected[$key]['comma_token'] += $target; + } + if (isset($param['default_token']) === true) { + $expected[$key]['default_token'] += $target; + } - /** - * Test helper. - * - * @param string $commentString The comment which preceeds the test. - * @param array $expected The expected function output. - * - * @return void - */ - private function getMethodParametersTestHelper($commentString, $expected) - { - $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); - $found = self::$phpcsFile->getMethodParameters($function); + if (isset($param['default_equal_token']) === true) { + $expected[$key]['default_equal_token'] += $target; + } + + if (isset($param['visibility_token']) === true && is_int($param['visibility_token']) === true) { + $expected[$key]['visibility_token'] += $target; + } + + if (isset($param['readonly_token']) === true) { + $expected[$key]['readonly_token'] += $target; + } + }//end foreach - $this->assertArraySubset($expected, $found, true); + $this->assertSame($expected, $found); }//end getMethodParametersTestHelper() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc index 0c592369a..7f572f66c 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc @@ -34,16 +34,23 @@ class MyClass { /* testMessyNullableReturnMethod */ public function myFunction() /* comment */ : - /* comment */ ? //comment + /* comment */ ? // phpcs:ignore Stnd.Cat.Sniff -- For reasons. array {} /* testReturnNamespace */ function myFunction(): \MyNamespace\MyClass {} /* testReturnMultilineNamespace */ + // Parse error in PHP 8.0. function myFunction(): \MyNamespace /** comment *\/ comment */ \MyClass /* comment */ \Foo {} + + /* testReturnUnqualifiedName */ + private function myFunction(): ?MyClass {} + + /* testReturnPartiallyQualifiedName */ + function myFunction(): Sub\Level\MyClass {} } abstract class MyClass @@ -72,6 +79,11 @@ class ReturnMe { private function myFunction(): static { return $this; } + + /* testReturnTypeNullableStatic */ + function myNullableFunction(): ?static { + return $this; + } } /* testPHP8MixedTypeHint */ @@ -102,11 +114,11 @@ function unionTypesAllPseudoTypes($var) : false|MIXED|self|parent|static|iterabl $closure = function () use($a) :?int|float {}; /* testPHP8PseudoTypeNull */ -// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeNull(): null {} /* testPHP8PseudoTypeFalse */ -// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeFalse(): false {} /* testPHP8PseudoTypeFalseAndBool */ @@ -150,3 +162,65 @@ $closure = function (): string&int {}; /* testPHP81NullableIntersectionTypes */ // Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. $closure = function (): ?Foo&Bar {}; + +/* testPHP82PseudoTypeTrue */ +function pseudoTypeTrue(): ?true {} + +/* testPHP82PseudoTypeFalseAndTrue */ +// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. +function pseudoTypeFalseAndTrue(): true|false {} + +/* testPHP82DNFType */ +function hasDNFType() : bool|(Foo&Bar)|string {} + +abstract class AbstractClass { + /* testPHP82DNFTypeAbstractMethod */ + abstract protected function abstractMethodDNFType() : float|(Foo&Bar); +} + +/* testPHP82DNFTypeIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +function illegalNullableDNF(): ?(A&\Pck\B)|bool {} + +/* testPHP82DNFTypeClosure */ +$closure = function() : object|(namespace\Foo&Countable) {}; + +/* testPHP82DNFTypeFn */ +// Intentional fatal error - void type cannot be combined with DNF. +$arrow = fn() : null|(Partially\Qualified&Traversable)|void => do_something(); + +/* testNotAFunction */ +return true; + +/* testPhpcsIssue1264 */ +function foo() : array { + echo $foo; +} + +/* testArrowFunctionArrayReturnValue */ +$fn = fn(): array => [a($a, $b)]; + +/* testArrowFunctionReturnByRef */ +fn&(?string $a) : ?string => $b; + +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + +/* testFunctionDeclarationNestedInTernaryPHPCS2975 */ +return (!$a ? [ new class { public function b(): c {} } ] : []); + +/* testClosureWithUseNoReturnType */ +$closure = function () use($a) /*comment*/ {}; + +/* testClosureWithUseNoReturnTypeIllegalUseProp */ +$closure = function () use ($this->prop){}; + +/* testClosureWithUseWithReturnType */ +$closure = function () use /*comment*/ ($a): Type {}; + +/* testClosureWithUseMultiParamWithReturnType */ +$closure = function () use ($a, &$b, $c, $d, $e, $f, $g): ?array {}; + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php index 66f4eea3e..fff60b9c4 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php @@ -1,20 +1,78 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class GetMethodPropertiesTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodProperties + */ +final class GetMethodPropertiesTest extends AbstractMethodUnitTest { + /** + * Test receiving an expected exception when a non function token is passed. + * + * @param string $commentString The comment which preceeds the test. + * @param string|int|array $targetTokenType The token type to search for after $commentString. + * + * @dataProvider dataNotAFunctionException + * + * @return void + */ + public function testNotAFunctionException($commentString, $targetTokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); + + $next = $this->getTargetToken($commentString, $targetTokenType); + self::$phpcsFile->getMethodProperties($next); + + }//end testNotAFunctionException() + + + /** + * Data Provider. + * + * @see testNotAFunctionException() For the array format. + * + * @return array>> + */ + public static function dataNotAFunctionException() + { + return [ + 'return' => [ + 'commentString' => '/* testNotAFunction */', + 'targetTokenType' => T_RETURN, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + 'commentString' => '/* testFunctionCallFnPHPCS353-354 */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + 'fn-live-coding' => [ + 'commentString' => '/* testArrowFunctionLiveCoding */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + ]; + + }//end dataNotAFunctionException() + + /** * Test a basic function. * @@ -23,14 +81,16 @@ class GetMethodPropertiesTest extends AbstractMethodUnitTest public function testBasicFunction() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -45,15 +105,18 @@ public function testBasicFunction() */ public function testReturnFunction() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'array', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 11, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -68,15 +131,18 @@ public function testReturnFunction() */ public function testNestedClosure() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -92,14 +158,16 @@ public function testNestedClosure() public function testBasicMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -115,14 +183,16 @@ public function testBasicMethod() public function testPrivateStaticMethod() { $expected = [ - 'scope' => 'private', - 'scope_specified' => true, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => true, - 'has_body' => true, + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -138,14 +208,16 @@ public function testPrivateStaticMethod() public function testFinalMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => true, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => true, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -160,15 +232,18 @@ public function testFinalMethod() */ public function testProtectedReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'protected', - 'scope_specified' => true, - 'return_type' => 'int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'int', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -183,15 +258,18 @@ public function testProtectedReturnMethod() */ public function testPublicReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => 'array', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'array', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -206,15 +284,18 @@ public function testPublicReturnMethod() */ public function testNullableReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '?array', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -229,15 +310,18 @@ public function testNullableReturnMethod() */ public function testMessyNullableReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '?array', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 18, + 'return_type_end_token' => 18, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -252,15 +336,18 @@ public function testMessyNullableReturnMethod() */ public function testReturnNamespace() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '\MyNamespace\MyClass', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass', + 'return_type_token' => 7, + 'return_type_end_token' => 10, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -269,21 +356,24 @@ public function testReturnNamespace() /** - * Test a method with a messy namespaces return type. + * Test a method with a messy namespaced return type. * * @return void */ public function testReturnMultilineNamespace() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '\MyNamespace\MyClass\Foo', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass\Foo', + 'return_type_token' => 7, + 'return_type_end_token' => 23, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -291,6 +381,58 @@ public function testReturnMultilineNamespace() }//end testReturnMultilineNamespace() + /** + * Test a method with an unqualified named return type. + * + * @return void + */ + public function testReturnUnqualifiedName() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '?MyClass', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnUnqualifiedName() + + + /** + * Test a method with a partially qualified namespaced return type. + * + * @return void + */ + public function testReturnPartiallyQualifiedName() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Sub\Level\MyClass', + 'return_type_token' => 7, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnPartiallyQualifiedName() + + /** * Test a basic abstract method. * @@ -299,14 +441,16 @@ public function testReturnMultilineNamespace() public function testAbstractMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => true, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -321,15 +465,18 @@ public function testAbstractMethod() */ public function testAbstractReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'protected', - 'scope_specified' => true, - 'return_type' => 'bool', - 'nullable_return_type' => false, - 'is_abstract' => true, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'bool', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -345,14 +492,16 @@ public function testAbstractReturnMethod() public function testInterfaceMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -367,15 +516,18 @@ public function testInterfaceMethod() */ public function testArrowFunction() { + // Offsets are relative to the T_FN token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => true, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 9, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -390,15 +542,18 @@ public function testArrowFunction() */ public function testReturnTypeStatic() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'private', - 'scope_specified' => true, - 'return_type' => 'static', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => 'static', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -406,6 +561,32 @@ public function testReturnTypeStatic() }//end testReturnTypeStatic() + /** + * Test a function with return type "?static". + * + * @return void + */ + public function testReturnTypeNullableStatic() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?static', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnTypeNullableStatic() + + /** * Test a function with return type "mixed". * @@ -413,15 +594,18 @@ public function testReturnTypeStatic() */ public function testPHP8MixedTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'mixed', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'mixed', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -436,15 +620,18 @@ public function testPHP8MixedTypeHint() */ public function testPHP8MixedTypeHintNullable() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?mixed', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?mixed', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -459,15 +646,18 @@ public function testPHP8MixedTypeHintNullable() */ public function testNamespaceOperatorTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?namespace\Name', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?namespace\Name', + 'return_type_token' => 9, + 'return_type_end_token' => 11, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -482,15 +672,18 @@ public function testNamespaceOperatorTypeHint() */ public function testPHP8UnionTypesSimple() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int|float', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|float', + 'return_type_token' => 9, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -505,15 +698,18 @@ public function testPHP8UnionTypesSimple() */ public function testPHP8UnionTypesTwoClasses() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'MyClassA|\Package\MyClassB', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA|\Package\MyClassB', + 'return_type_token' => 6, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -528,15 +724,18 @@ public function testPHP8UnionTypesTwoClasses() */ public function testPHP8UnionTypesAllBaseTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'array|bool|callable|int|float|null|Object|string', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array|bool|callable|int|float|null|Object|string', + 'return_type_token' => 8, + 'return_type_end_token' => 22, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -547,19 +746,24 @@ public function testPHP8UnionTypesAllBaseTypes() /** * Verify recognition of PHP8 union type declaration with all pseudo types. * + * Note: "Resource" is not a type, but seen as a class name. + * * @return void */ public function testPHP8UnionTypesAllPseudoTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void', + 'return_type_token' => 9, + 'return_type_end_token' => 23, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -574,15 +778,18 @@ public function testPHP8UnionTypesAllPseudoTypes() */ public function testPHP8UnionTypesNullable() { + // Offsets are relative to the T_CLOSURE token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?int|float', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?int|float', + 'return_type_token' => 12, + 'return_type_end_token' => 14, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -597,15 +804,18 @@ public function testPHP8UnionTypesNullable() */ public function testPHP8PseudoTypeNull() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'null', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -620,15 +830,18 @@ public function testPHP8PseudoTypeNull() */ public function testPHP8PseudoTypeFalse() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'false', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -643,15 +856,18 @@ public function testPHP8PseudoTypeFalse() */ public function testPHP8PseudoTypeFalseAndBool() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'bool|false', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|false', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -666,15 +882,18 @@ public function testPHP8PseudoTypeFalseAndBool() */ public function testPHP8ObjectAndClass() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'object|ClassName', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|ClassName', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -689,15 +908,18 @@ public function testPHP8ObjectAndClass() */ public function testPHP8PseudoTypeIterableAndArray() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => 'iterable|array|Traversable', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'iterable|array|Traversable', + 'return_type_token' => 7, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -712,15 +934,18 @@ public function testPHP8PseudoTypeIterableAndArray() */ public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int|string|INT', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|string|INT', + 'return_type_token' => 7, + 'return_type_end_token' => 17, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -735,15 +960,18 @@ public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() */ public function testPHP81NeverType() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'never', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'never', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -758,15 +986,18 @@ public function testPHP81NeverType() */ public function testPHP81NullableNeverType() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?never', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?never', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -781,15 +1012,18 @@ public function testPHP81NullableNeverType() */ public function testPHP8IntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'Foo&Bar', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Foo&Bar', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -804,15 +1038,18 @@ public function testPHP8IntersectionTypes() */ public function testPHP81MoreIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'return_type_token' => 7, + 'return_type_end_token' => 17, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -827,15 +1064,18 @@ public function testPHP81MoreIntersectionTypes() */ public function testPHP81IntersectionArrowFunction() { + // Offsets are relative to the T_FN token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'MyClassA&\Package\MyClassB', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB', + 'return_type_token' => 6, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -850,15 +1090,18 @@ public function testPHP81IntersectionArrowFunction() */ public function testPHP81IllegalIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'string&int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'string&int', + 'return_type_token' => 6, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -873,15 +1116,18 @@ public function testPHP81IllegalIntersectionTypes() */ public function testPHP81NullableIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?Foo&Bar', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?Foo&Bar', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -889,11 +1135,408 @@ public function testPHP81NullableIntersectionTypes() }//end testPHP81NullableIntersectionTypes() + /** + * Verify recognition of PHP 8.2 stand-alone `true` type. + * + * @return void + */ + public function testPHP82PseudoTypeTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?true', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeTrue() + + + /** + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. + * + * @return void + */ + public function testPHP82PseudoTypeFalseAndTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'true|false', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeFalseAndTrue() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration. + * + * @return void + */ + public function testPHP82DNFType() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|(Foo&Bar)|string', + 'return_type_token' => 8, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFType() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an abstract method. + * + * @return void + */ + public function testPHP82DNFTypeAbstractMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'float|(Foo&Bar)', + 'return_type_token' => 8, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeAbstractMethod() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration with illegal nullability. + * + * @return void + */ + public function testPHP82DNFTypeIllegalNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?(A&\Pck\B)|bool', + 'return_type_token' => 8, + 'return_type_end_token' => 17, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on a closure. + * + * @return void + */ + public function testPHP82DNFTypeClosure() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|(namespace\Foo&Countable)', + 'return_type_token' => 6, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeClosure() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an arrow function. + * + * @return void + */ + public function testPHP82DNFTypeFn() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null|(Partially\Qualified&Traversable)|void', + 'return_type_token' => 6, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeFn() + + + /** + * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/1264 + * + * @return void + */ + public function testPhpcsIssue1264() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPhpcsIssue1264() + + + /** + * Test handling of incorrect tokenization of array return type declarations for arrow functions + * in a very specific code sample in PHPCS < 3.5.4. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2773 + * + * @return void + */ + public function testArrowFunctionArrayReturnValue() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 5, + 'return_type_end_token' => 5, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionArrayReturnValue() + + + /** + * Test handling of an arrow function returning by reference. + * + * @return void + */ + public function testArrowFunctionReturnByRef() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?string', + 'return_type_token' => 12, + 'return_type_end_token' => 12, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionReturnByRef() + + + /** + * Test handling of function declaration nested in a ternary, where the colon for the + * return type was incorrectly tokenized as T_INLINE_ELSE prior to PHPCS 3.5.7. + * + * @return void + */ + public function testFunctionDeclarationNestedInTernaryPHPCS2975() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'c', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testFunctionDeclarationNestedInTernaryPHPCS2975() + + + /** + * Test handling of closure declarations with a use variable import without a return type declaration. + * + * @return void + */ + public function testClosureWithUseNoReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseNoReturnType() + + + /** + * Test handling of closure declarations with an illegal use variable for a property import (not allowed in PHP) + * without a return type declaration. + * + * @return void + */ + public function testClosureWithUseNoReturnTypeIllegalUseProp() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseNoReturnTypeIllegalUseProp() + + + /** + * Test handling of closure declarations with a use variable import with a return type declaration. + * + * @return void + */ + public function testClosureWithUseWithReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Type', + 'return_type_token' => 14, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseWithReturnType() + + + /** + * Test handling of closure declarations with a use variable import with a return type declaration. + * + * @return void + */ + public function testClosureWithUseMultiParamWithReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?array', + 'return_type_token' => 32, + 'return_type_end_token' => 32, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseMultiParamWithReturnType() + + /** * Test helper. * - * @param string $commentString The comment which preceeds the test. - * @param array $expected The expected function output. + * @param string $commentString The comment which preceeds the test. + * @param array $expected The expected function output. * * @return void */ @@ -902,7 +1545,16 @@ private function getMethodPropertiesTestHelper($commentString, $expected) $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); $found = self::$phpcsFile->getMethodProperties($function); - $this->assertArraySubset($expected, $found, true); + // Convert offsets to absolute positions in the token stream. + if (is_int($expected['return_type_token']) === true) { + $expected['return_type_token'] += $function; + } + + if (is_int($expected['return_type_end_token']) === true) { + $expected['return_type_end_token'] += $function; + } + + $this->assertSame($expected, $found); }//end getMethodPropertiesTestHelper() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc new file mode 100644 index 000000000..ace5a9bd4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc @@ -0,0 +1,25 @@ + 20; +} + +/* testEchoWithTabs */ +echo 'foo', + 'bar' , + 'baz'; + +/* testEndOfFile */ +echo $foo; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php new file mode 100644 index 000000000..7e7974951 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php @@ -0,0 +1,334 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getTokensAsString method. + * + * @covers \PHP_CodeSniffer\Files\File::getTokensAsString + */ +final class GetTokensAsStringTest extends AbstractMethodUnitTest +{ + + + /** + * Test passing a non-existent token pointer. + * + * @return void + */ + public function testNonExistentToken() + { + $this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack'); + + self::$phpcsFile->getTokensAsString(100000, 10); + + }//end testNonExistentToken() + + + /** + * Test passing a non integer `$start`, like the result of a failed $phpcsFile->findNext(). + * + * @return void + */ + public function testNonIntegerStart() + { + $this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack'); + + self::$phpcsFile->getTokensAsString(false, 10); + + }//end testNonIntegerStart() + + + /** + * Test passing a non integer `$length`. + * + * @return void + */ + public function testNonIntegerLength() + { + $result = self::$phpcsFile->getTokensAsString(10, false); + $this->assertSame('', $result); + + $result = self::$phpcsFile->getTokensAsString(10, 1.5); + $this->assertSame('', $result); + + }//end testNonIntegerLength() + + + /** + * Test passing a zero or negative `$length`. + * + * @return void + */ + public function testLengthEqualToOrLessThanZero() + { + $result = self::$phpcsFile->getTokensAsString(10, -10); + $this->assertSame('', $result); + + $result = self::$phpcsFile->getTokensAsString(10, 0); + $this->assertSame('', $result); + + }//end testLengthEqualToOrLessThanZero() + + + /** + * Test passing a `$length` beyond the end of the file. + * + * @return void + */ + public function testLengthBeyondEndOfFile() + { + $semicolon = $this->getTargetToken('/* testEndOfFile */', T_SEMICOLON); + $result = self::$phpcsFile->getTokensAsString($semicolon, 20); + $this->assertSame( + '; +', + $result + ); + + }//end testLengthBeyondEndOfFile() + + + /** + * Test getting a token set as a string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $startTokenType The type of token(s) to look for for the start of the string. + * @param int $length Token length to get. + * @param string $expected The expected function return value. + * + * @dataProvider dataGetTokensAsString + * + * @return void + */ + public function testGetTokensAsString($testMarker, $startTokenType, $length, $expected) + { + $start = $this->getTargetToken($testMarker, $startTokenType); + $result = self::$phpcsFile->getTokensAsString($start, $length); + $this->assertSame($expected, $result); + + }//end testGetTokensAsString() + + + /** + * Data provider. + * + * @see testGetTokensAsString() For the array format. + * + * @return array> + */ + public static function dataGetTokensAsString() + { + return [ + 'length-0' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 0, + 'expected' => '', + ], + 'length-1' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 1, + 'expected' => '1', + ], + 'length-2' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 2, + 'expected' => '1 ', + ], + 'length-3' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 3, + 'expected' => '1 +', + ], + 'length-4' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 4, + 'expected' => '1 + ', + ], + 'length-5' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 5, + 'expected' => '1 + 2', + ], + 'length-6' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 6, + 'expected' => '1 + 2 ', + ], + 'length-7' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 7, + 'expected' => '1 + 2 +', + ], + 'length-8' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 8, + 'expected' => '1 + 2 + +', + ], + 'length-9' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 9, + 'expected' => '1 + 2 + + ', + ], + 'length-10' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 10, + 'expected' => '1 + 2 + + // Comment. +', + ], + 'length-11' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 11, + 'expected' => '1 + 2 + + // Comment. + ', + ], + 'length-12' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 12, + 'expected' => '1 + 2 + + // Comment. + 3', + ], + 'length-13' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 13, + 'expected' => '1 + 2 + + // Comment. + 3 ', + ], + 'length-14' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 14, + 'expected' => '1 + 2 + + // Comment. + 3 +', + ], + 'length-34' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 34, + 'expected' => '1 + 2 + + // Comment. + 3 + 4 + + 5 + 6 + 7 > 20;', + ], + 'namespace' => [ + 'testMarker' => '/* testNamespace */', + 'startTokenType' => T_NAMESPACE, + 'length' => 8, + 'expected' => 'namespace Foo\Bar\Baz;', + ], + 'use-with-comments' => [ + 'testMarker' => '/* testUseWithComments */', + 'startTokenType' => T_USE, + 'length' => 17, + 'expected' => 'use Foo /*comment*/ \ Bar + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + \ Bah;', + ], + 'echo-with-tabs' => [ + 'testMarker' => '/* testEchoWithTabs */', + 'startTokenType' => T_ECHO, + 'length' => 13, + 'expected' => 'echo \'foo\', + \'bar\' , + \'baz\';', + ], + 'end-of-file' => [ + 'testMarker' => '/* testEndOfFile */', + 'startTokenType' => T_ECHO, + 'length' => 4, + 'expected' => 'echo $foo;', + ], + ]; + + }//end dataGetTokensAsString() + + + /** + * Test getting a token set as a string with the original, non tab-replaced content. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $startTokenType The type of token(s) to look for for the start of the string. + * @param int $length Token length to get. + * @param string $expected The expected function return value. + * + * @dataProvider dataGetOrigContent + * + * @return void + */ + public function testGetOrigContent($testMarker, $startTokenType, $length, $expected) + { + $start = $this->getTargetToken($testMarker, $startTokenType); + $result = self::$phpcsFile->getTokensAsString($start, $length, true); + $this->assertSame($expected, $result); + + }//end testGetOrigContent() + + + /** + * Data provider. + * + * @see testGetOrigContent() For the array format. + * + * @return array> + */ + public static function dataGetOrigContent() + { + return [ + 'use-with-comments' => [ + 'testMarker' => '/* testUseWithComments */', + 'startTokenType' => T_USE, + 'length' => 17, + 'expected' => 'use Foo /*comment*/ \ Bar + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + \ Bah;', + ], + 'echo-with-tabs' => [ + 'testMarker' => '/* testEchoWithTabs */', + 'startTokenType' => T_ECHO, + 'length' => 13, + 'expected' => 'echo \'foo\', + \'bar\' , + \'baz\';', + ], + 'end-of-file' => [ + 'testMarker' => '/* testEndOfFile */', + 'startTokenType' => T_ECHO, + 'length' => 4, + 'expected' => 'echo $foo;', + ], + ]; + + }//end dataGetOrigContent() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc index f71e2639d..05af83905 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc @@ -1,6 +1,8 @@ getValue(); /* testAssignByReferenceE */ $collection = &collector(); +/* testAssignByReferenceF */ +$collection ??= &collector(); + +/* testShortListAssignByReferenceNoKeyA */ +[ + &$a, + /* testShortListAssignByReferenceNoKeyB */ + &$b, + /* testNestedShortListAssignByReferenceNoKey */ + [$c, &$d] +] = $array; + +/* testLongListAssignByReferenceNoKeyA */ +list($a, &$b, list(/* testLongListAssignByReferenceNoKeyB */ &$c, /* testLongListAssignByReferenceNoKeyC */ &$d)) = $array; + +[ + /* testNestedShortListAssignByReferenceWithKeyA */ + 'a' => [&$a, $b], + /* testNestedShortListAssignByReferenceWithKeyB */ + 'b' => [$c, &$d] +] = $array; + + +/* testLongListAssignByReferenceWithKeyA */ +list(get_key()[1] => &$e) = [1, 2, 3]; + /* testPassByReferenceA */ functionCall(&$something, $somethingElse); @@ -128,6 +156,9 @@ functionCall($something, &\SomeNS\SomeClass::$somethingElse); /* testPassByReferenceJ */ functionCall($something, &namespace\SomeClass::$somethingElse); +/* testPassByReferencePartiallyQualifiedName */ +functionCall($something, &Sub\Level\SomeClass::$somethingElse); + /* testNewByReferenceA */ $foobar2 = &new Foobar(); @@ -137,9 +168,27 @@ functionCall( $something , &new Foobar() ); /* testUseByReference */ $closure = function() use (&$var){}; +/* testUseByReferenceWithCommentFirstParam */ +$closure = function() use /*comment*/ (&$value){}; + +/* testUseByReferenceWithCommentSecondParam */ +$closure = function() use /*comment*/ ($varA, &$varB){}; + /* testArrowFunctionReturnByReference */ fn&($x) => $x; +$closure = function ( + /* testBitwiseAndExactParameterA */ + $a = MY_CONSTANT & parent::OTHER_CONSTANT, + /* testPassByReferenceExactParameterB */ + &$b, + /* testPassByReferenceExactParameterC */ + &...$c, + /* testBitwiseAndExactParameterD */ + $d = E_NOTICE & E_STRICT, +) {}; + +// Issue PHPCS#3049. /* testArrowFunctionPassByReferenceA */ $fn = fn(array &$one) => 1; @@ -148,3 +197,20 @@ $fn = fn($param, &...$moreParams) => 1; /* testClosureReturnByReference */ $closure = function &($param) use ($value) {}; + +/* testBitwiseAndArrowFunctionInDefault */ +$fn = fn( $one = E_NOTICE & E_STRICT) => 1; + +/* testIntersectionIsNotReference */ +function intersect(Foo&Bar $param) {} + +/* testDNFTypeIsNotReference */ +$fn = fn((Foo&\Bar)|null /* testParamPassByReference */ &$param) => $param; + +/* testTokenizerIssue1284PHPCSlt280A */ +if ($foo) {} +[&$a, /* testTokenizerIssue1284PHPCSlt280B */ &$b] = $c; + +/* testTokenizerIssue1284PHPCSlt280C */ +if ($foo) {} +[&$a, $b]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php index ea2dddbad..5b977de7a 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php @@ -1,33 +1,85 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class IsReferenceTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::isReference method. + * + * @covers \PHP_CodeSniffer\Files\File::isReference + */ +final class IsReferenceTest extends AbstractMethodUnitTest { + /** + * Test that false is returned when a non-"bitwise and" token is passed. + * + * @param string $testMarker Comment which precedes the test case. + * @param array $targetTokens Type of tokens to look for. + * + * @dataProvider dataNotBitwiseAndToken + * + * @return void + */ + public function testNotBitwiseAndToken($testMarker, $targetTokens) + { + $targetTokens[] = T_BITWISE_AND; + + $target = $this->getTargetToken($testMarker, $targetTokens); + $this->assertFalse(self::$phpcsFile->isReference($target)); + + }//end testNotBitwiseAndToken() + + + /** + * Data provider. + * + * @see testNotBitwiseAndToken() + * + * @return array>> + */ + public static function dataNotBitwiseAndToken() + { + return [ + 'Not ampersand token at all' => [ + 'testMarker' => '/* testBitwiseAndA */', + 'targetTokens' => [T_STRING], + ], + 'ampersand in intersection type' => [ + 'testMarker' => '/* testIntersectionIsNotReference */', + 'targetTokens' => [T_TYPE_INTERSECTION], + ], + 'ampersand in DNF type' => [ + 'testMarker' => '/* testDNFTypeIsNotReference */', + 'targetTokens' => [T_TYPE_INTERSECTION], + ], + ]; + + }//end dataNotBitwiseAndToken() + + /** * Test correctly identifying whether a "bitwise and" token is a reference or not. * - * @param string $identifier Comment which precedes the test case. + * @param string $testMarker Comment which precedes the test case. * @param bool $expected Expected function output. * * @dataProvider dataIsReference * * @return void */ - public function testIsReference($identifier, $expected) + public function testIsReference($testMarker, $expected) { - $bitwiseAnd = $this->getTargetToken($identifier, T_BITWISE_AND); + $bitwiseAnd = $this->getTargetToken($testMarker, T_BITWISE_AND); $result = self::$phpcsFile->isReference($bitwiseAnd); $this->assertSame($expected, $result); @@ -39,206 +91,302 @@ public function testIsReference($identifier, $expected) * * @see testIsReference() * - * @return array + * @return array> */ - public function dataIsReference() + public static function dataIsReference() { return [ - [ - '/* testBitwiseAndA */', - false, + 'issue-1971-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271A */', + 'expected' => true, + ], + 'issue-1971-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271B */', + 'expected' => true, + ], + 'bitwise and: param in function call' => [ + 'testMarker' => '/* testBitwiseAndA */', + 'expected' => false, + ], + 'bitwise and: in unkeyed short array, first value' => [ + 'testMarker' => '/* testBitwiseAndB */', + 'expected' => false, + ], + 'bitwise and: in unkeyed short array, last value' => [ + 'testMarker' => '/* testBitwiseAndC */', + 'expected' => false, + ], + 'bitwise and: in unkeyed long array, last value' => [ + 'testMarker' => '/* testBitwiseAndD */', + 'expected' => false, + ], + 'bitwise and: in keyed short array, last value' => [ + 'testMarker' => '/* testBitwiseAndE */', + 'expected' => false, + ], + 'bitwise and: in keyed long array, last value' => [ + 'testMarker' => '/* testBitwiseAndF */', + 'expected' => false, + ], + 'bitwise and: in assignment' => [ + 'testMarker' => '/* testBitwiseAndG */', + 'expected' => false, + ], + 'bitwise and: in param default value in function declaration' => [ + 'testMarker' => '/* testBitwiseAndH */', + 'expected' => false, + ], + 'bitwise and: in param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndI */', + 'expected' => false, + ], + 'reference: function declared to return by reference' => [ + 'testMarker' => '/* testFunctionReturnByReference */', + 'expected' => true, + ], + 'reference: only param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceA */', + 'expected' => true, + ], + 'reference: last param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceB */', + 'expected' => true, + ], + 'reference: only param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceC */', + 'expected' => true, + ], + 'reference: last param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceD */', + 'expected' => true, + ], + 'reference: typed param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceE */', + 'expected' => true, + ], + 'reference: typed param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceF */', + 'expected' => true, + ], + 'reference: variadic param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceG */', + 'expected' => true, + ], + 'reference: foreach value' => [ + 'testMarker' => '/* testForeachValueByReference */', + 'expected' => true, + ], + 'reference: foreach key' => [ + 'testMarker' => '/* testForeachKeyByReference */', + 'expected' => true, + ], + 'reference: keyed short array, first value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceA */', + 'expected' => true, + ], + 'reference: keyed short array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceB */', + 'expected' => true, + ], + 'reference: unkeyed short array, only value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceC */', + 'expected' => true, + ], + 'reference: unkeyed short array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceD */', + 'expected' => true, ], - [ - '/* testBitwiseAndB */', - false, + 'reference: keyed long array, first value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceE */', + 'expected' => true, ], - [ - '/* testBitwiseAndC */', - false, + 'reference: keyed long array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceF */', + 'expected' => true, ], - [ - '/* testBitwiseAndD */', - false, + 'reference: unkeyed long array, only value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceG */', + 'expected' => true, ], - [ - '/* testBitwiseAndE */', - false, + 'reference: unkeyed long array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceH */', + 'expected' => true, ], - [ - '/* testBitwiseAndF */', - false, + 'reference: variable, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceA */', + 'expected' => true, ], - [ - '/* testBitwiseAndG */', - false, + 'reference: variable, assign by reference, spacing variation' => [ + 'testMarker' => '/* testAssignByReferenceB */', + 'expected' => true, ], - [ - '/* testBitwiseAndH */', - false, + 'reference: variable, assign by reference, concat assign' => [ + 'testMarker' => '/* testAssignByReferenceC */', + 'expected' => true, ], - [ - '/* testBitwiseAndI */', - false, + 'reference: property, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceD */', + 'expected' => true, ], - [ - '/* testFunctionReturnByReference */', - true, + 'reference: function return value, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceE */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceA */', - true, + 'reference: function return value, assign by reference, null coalesce assign' => [ + 'testMarker' => '/* testAssignByReferenceF */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceB */', - true, + 'reference: unkeyed short list, first var, assign by reference' => [ + 'testMarker' => '/* testShortListAssignByReferenceNoKeyA */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceC */', - true, + 'reference: unkeyed short list, second var, assign by reference' => [ + 'testMarker' => '/* testShortListAssignByReferenceNoKeyB */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceD */', - true, + 'reference: unkeyed short list, nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceNoKey */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceE */', - true, + 'reference: unkeyed long list, second var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyA */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceF */', - true, + 'reference: unkeyed long list, first nested var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyB */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceG */', - true, + 'reference: unkeyed long list, last nested var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyC */', + 'expected' => true, ], - [ - '/* testForeachValueByReference */', - true, + 'reference: keyed short list, first nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyA */', + 'expected' => true, ], - [ - '/* testForeachKeyByReference */', - true, + 'reference: keyed short list, last nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyB */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceA */', - true, + 'reference: keyed long list, only var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceWithKeyA */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceB */', - true, + 'reference: first param in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceA */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceC */', - true, + 'reference: last param in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceB */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceD */', - true, + 'reference: property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceC */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceE */', - true, + 'reference: hierarchical self property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceD */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceF */', - true, + 'reference: hierarchical parent property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceE */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceG */', - true, + 'reference: hierarchical static property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceF */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceH */', - true, + 'reference: static property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceG */', + 'expected' => true, ], - [ - '/* testAssignByReferenceA */', - true, + 'reference: static property in function call, first with FQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceH */', + 'expected' => true, ], - [ - '/* testAssignByReferenceB */', - true, + 'reference: static property in function call, last with FQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceI */', + 'expected' => true, ], - [ - '/* testAssignByReferenceC */', - true, + 'reference: static property in function call, last with namespace relative name, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceJ */', + 'expected' => true, ], - [ - '/* testAssignByReferenceD */', - true, + 'reference: static property in function call, last with PQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferencePartiallyQualifiedName */', + 'expected' => true, ], - [ - '/* testAssignByReferenceE */', - true, + 'reference: new by reference' => [ + 'testMarker' => '/* testNewByReferenceA */', + 'expected' => true, ], - [ - '/* testPassByReferenceA */', - true, + 'reference: new by reference as function call param' => [ + 'testMarker' => '/* testNewByReferenceB */', + 'expected' => true, ], - [ - '/* testPassByReferenceB */', - true, + 'reference: closure use by reference' => [ + 'testMarker' => '/* testUseByReference */', + 'expected' => true, ], - [ - '/* testPassByReferenceC */', - true, + 'reference: closure use by reference, first param, with comment' => [ + 'testMarker' => '/* testUseByReferenceWithCommentFirstParam */', + 'expected' => true, ], - [ - '/* testPassByReferenceD */', - true, + 'reference: closure use by reference, last param, with comment' => [ + 'testMarker' => '/* testUseByReferenceWithCommentSecondParam */', + 'expected' => true, ], - [ - '/* testPassByReferenceE */', - true, + 'reference: arrow fn declared to return by reference' => [ + 'testMarker' => '/* testArrowFunctionReturnByReference */', + 'expected' => true, ], - [ - '/* testPassByReferenceF */', - true, + 'bitwise and: first param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndExactParameterA */', + 'expected' => false, ], - [ - '/* testPassByReferenceG */', - true, + 'reference: param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceExactParameterB */', + 'expected' => true, ], - [ - '/* testPassByReferenceH */', - true, + 'reference: variadic param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceExactParameterC */', + 'expected' => true, ], - [ - '/* testPassByReferenceI */', - true, + 'bitwise and: last param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndExactParameterD */', + 'expected' => false, ], - [ - '/* testPassByReferenceJ */', - true, + 'reference: typed param in arrow fn declaration, pass by reference' => [ + 'testMarker' => '/* testArrowFunctionPassByReferenceA */', + 'expected' => true, ], - [ - '/* testNewByReferenceA */', - true, + 'reference: variadic param in arrow fn declaration, pass by reference' => [ + 'testMarker' => '/* testArrowFunctionPassByReferenceB */', + 'expected' => true, ], - [ - '/* testNewByReferenceB */', - true, + 'reference: closure declared to return by reference' => [ + 'testMarker' => '/* testClosureReturnByReference */', + 'expected' => true, ], - [ - '/* testUseByReference */', - true, + 'bitwise and: param default value in arrow fn declaration' => [ + 'testMarker' => '/* testBitwiseAndArrowFunctionInDefault */', + 'expected' => false, ], - [ - '/* testArrowFunctionReturnByReference */', - true, + 'reference: param pass by ref in arrow function' => [ + 'testMarker' => '/* testParamPassByReference */', + 'expected' => true, ], - [ - '/* testArrowFunctionPassByReferenceA */', - true, + 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280A */', + 'expected' => true, ], - [ - '/* testArrowFunctionPassByReferenceB */', - true, + 'issue-1284-short-list-directly-after-close-curly-control-structure-second-item' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280B */', + 'expected' => true, ], - [ - '/* testClosureReturnByReference */', - true, + 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280C */', + 'expected' => true, ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php new file mode 100644 index 000000000..3627d4aa2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php @@ -0,0 +1,250 @@ + + * @copyright 2023 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Filters; + +use PHP_CodeSniffer\Filters\Filter; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; +use RecursiveIteratorIterator; + +/** + * Base functionality and utilities for testing Filter classes. + */ +abstract class AbstractFilterTestCase extends TestCase +{ + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Config + */ + protected static $config; + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + protected static $ruleset; + + + /** + * Initialize the config and ruleset objects. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + self::$config = new ConfigDouble(['--extensions=php,inc/php,js,css']); + self::$ruleset = new Ruleset(self::$config); + + }//end initializeConfigAndRuleset() + + + /** + * Clean up after finished test by resetting all static properties on the Config class to their default values. + * + * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()} + * method. + * + * @afterClass + * + * @return void + */ + public static function reset() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when `self::$phpcsFile` is reset, but we can't definitively rely on that). + if (isset(self::$config) === true) { + self::$config->__destruct(); + } + + }//end reset() + + + /** + * Helper method to retrieve a mock object for a Filter class. + * + * The `setMethods()` method was silently deprecated in PHPUnit 9 and removed in PHPUnit 10. + * + * Note: direct access to the `getMockBuilder()` method is soft deprecated as of PHPUnit 10, + * and expected to be hard deprecated in PHPUnit 11 and removed in PHPUnit 12. + * Dealing with that is something for a later iteration of the test suite. + * + * @param string $className Fully qualified name of the class under test. + * @param array $constructorArgs Optional. Array of parameters to pass to the class constructor. + * @param array|null $methodsToMock Optional. The methods to mock in the class under test. + * Needed for PHPUnit cross-version support as PHPUnit 4.x does + * not have a `setMethodsExcept()` method yet. + * If not passed, no methods will be replaced. + * + * @return \PHPUnit\Framework\MockObject\MockObject + */ + protected function getMockedClass($className, array $constructorArgs=[], $methodsToMock=null) + { + $mockedObj = $this->getMockBuilder($className); + + if (method_exists($mockedObj, 'onlyMethods') === true) { + // PHPUnit 8+. + if (is_array($methodsToMock) === true) { + return $mockedObj + ->setConstructorArgs($constructorArgs) + ->onlyMethods($methodsToMock) + ->getMock(); + } + + return $mockedObj->getMock() + ->setConstructorArgs($constructorArgs); + } + + // PHPUnit < 8. + return $mockedObj + ->setConstructorArgs($constructorArgs) + ->setMethods($methodsToMock) + ->getMock(); + + }//end getMockedClass() + + + /** + * Retrieve an array of files which were accepted by a filter. + * + * @param \PHP_CodeSniffer\Filters\Filter $filter The Filter object under test. + * + * @return array + */ + protected function getFilteredResultsAsArray(Filter $filter) + { + $iterator = new RecursiveIteratorIterator($filter); + $files = []; + foreach ($iterator as $file) { + $files[] = $file; + } + + return $files; + + }//end getFilteredResultsAsArray() + + + /** + * Retrieve the basedir to use for tests using the `getFakeFileList()` method. + * + * @return string + */ + protected static function getBaseDir() + { + return dirname(dirname(dirname(__DIR__))); + + }//end getBaseDir() + + + /** + * Retrieve a file list containing a range of paths for testing purposes. + * + * This list **must** contain files which exist in this project (well, except for some which don't exist + * purely for testing purposes), as `realpath()` is used in the logic under test and `realpath()` will + * return `false` for any non-existent files, which will automatically filter them out before + * we get to the code under test. + * + * Note this list does not include `.` and `..` as \PHP_CodeSniffer\Files\FileList uses `SKIP_DOTS`. + * + * @return array + */ + protected static function getFakeFileList() + { + $basedir = self::getBaseDir(); + return [ + $basedir.'/.gitignore', + $basedir.'/.yamllint.yml', + $basedir.'/phpcs.xml', + $basedir.'/phpcs.xml.dist', + $basedir.'/autoload.php', + $basedir.'/bin', + $basedir.'/bin/phpcs', + $basedir.'/bin/phpcs.bat', + $basedir.'/scripts', + $basedir.'/scripts/build-phar.php', + $basedir.'/src', + $basedir.'/src/WillNotExist.php', + $basedir.'/src/WillNotExist.bak', + $basedir.'/src/WillNotExist.orig', + $basedir.'/src/Ruleset.php', + $basedir.'/src/Generators', + $basedir.'/src/Generators/Markdown.php', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Docs', + $basedir.'/src/Standards/Generic/Docs/Classes', + $basedir.'/src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + $basedir.'/src/Standards/Generic/Tests', + $basedir.'/src/Standards/Generic/Tests/Classes', + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc', + // Will rarely exist when running the tests. + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc.bak', + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.2.inc', + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.php', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Docs', + $basedir.'/src/Standards/Squiz/Docs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml', + $basedir.'/src/Standards/Squiz/Sniffs', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ]; + + }//end getFakeFileList() + + + /** + * Translate Linux paths to Windows paths, when necessary. + * + * These type of tests should be able to run and pass on both *nix as well as Windows + * based dev systems. This method is a helper to allow for this. + * + * @param array> $paths A single or multi-dimensional array containing + * file paths. + * + * @return array> + */ + protected static function mapPathsToRuntimeOs(array $paths) + { + if (DIRECTORY_SEPARATOR !== '\\') { + return $paths; + } + + foreach ($paths as $key => $value) { + if (is_string($value) === true) { + $paths[$key] = strtr($value, '/', '\\\\'); + } else if (is_array($value) === true) { + $paths[$key] = self::mapPathsToRuntimeOs($value); + } + } + + return $paths; + + }//end mapPathsToRuntimeOs() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php index 2c9f57cd3..d4da0a248 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php @@ -5,75 +5,47 @@ * @author Willington Vega * @author Juliette Reinders Folmer * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Filters\Filter; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Filters\Filter; use PHP_CodeSniffer\Ruleset; -use PHPUnit\Framework\TestCase; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; +use RecursiveArrayIterator; -class AcceptTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Filters\Filter::accept method. + * + * @covers \PHP_CodeSniffer\Filters\Filter + */ +final class AcceptTest extends AbstractFilterTestCase { - /** - * The Config object. - * - * @var \PHP_CodeSniffer\Config - */ - protected static $config; - - /** - * The Ruleset object. - * - * @var \PHP_CodeSniffer\Ruleset - */ - protected static $ruleset; - - - /** - * Initialize the test. - * - * @return void - */ - public function setUp() - { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - - }//end setUp() - /** * Initialize the config and ruleset objects based on the `AcceptTest.xml` ruleset file. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function initializeConfigAndRuleset() { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // This test will be skipped. - return; - } - $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; - self::$config = new Config(["--standard=$standard", "--ignore=*/somethingelse/*"]); + self::$config = new ConfigDouble(["--standard=$standard", '--ignore=*/somethingelse/*']); self::$ruleset = new Ruleset(self::$config); - }//end setUpBeforeClass() + }//end initializeConfigAndRuleset() /** * Test filtering a file list for excluded paths. * - * @param array $inputPaths List of file paths to be filtered. - * @param array $expectedOutput Expected filtering result. + * @param array $inputPaths List of file paths to be filtered. + * @param array $expectedOutput Expected filtering result. * * @dataProvider dataExcludePatterns * @@ -81,16 +53,10 @@ public static function setUpBeforeClass() */ public function testExcludePatterns($inputPaths, $expectedOutput) { - $fakeDI = new \RecursiveArrayIterator($inputPaths); - $filter = new Filter($fakeDI, '/', self::$config, self::$ruleset); - $iterator = new \RecursiveIteratorIterator($filter); - $files = []; - - foreach ($iterator as $file) { - $files[] = $file; - } + $fakeDI = new RecursiveArrayIterator($inputPaths); + $filter = new Filter($fakeDI, '/', self::$config, self::$ruleset); - $this->assertEquals($expectedOutput, $files); + $this->assertSame($expectedOutput, $this->getFilteredResultsAsArray($filter)); }//end testExcludePatterns() @@ -100,34 +66,34 @@ public function testExcludePatterns($inputPaths, $expectedOutput) * * @see testExcludePatterns * - * @return array + * @return array>> */ - public function dataExcludePatterns() + public static function dataExcludePatterns() { $testCases = [ // Test top-level exclude patterns. - [ - [ + 'Non-sniff specific path based excludes from ruleset and command line are respected and don\'t filter out too much' => [ + 'inputPaths' => [ '/path/to/src/Main.php', '/path/to/src/Something/Main.php', '/path/to/src/Somethingelse/Main.php', '/path/to/src/SomethingelseEvenLonger/Main.php', '/path/to/src/Other/Main.php', ], - [ + 'expectedOutput' => [ '/path/to/src/Main.php', '/path/to/src/SomethingelseEvenLonger/Main.php', ], ], // Test ignoring standard/sniff specific exclude patterns. - [ - [ + 'Filter should not act on standard/sniff specific exclude patterns' => [ + 'inputPaths' => [ '/path/to/src/generic-project/Main.php', '/path/to/src/generic/Main.php', '/path/to/src/anything-generic/Main.php', ], - [ + 'expectedOutput' => [ '/path/to/src/generic-project/Main.php', '/path/to/src/generic/Main.php', '/path/to/src/anything-generic/Main.php', @@ -136,17 +102,7 @@ public function dataExcludePatterns() ]; // Allow these tests to work on Windows as well. - if (DIRECTORY_SEPARATOR === '\\') { - foreach ($testCases as $key => $case) { - foreach ($case as $nr => $param) { - foreach ($param as $file => $value) { - $testCases[$key][$nr][$file] = strtr($value, '/', '\\'); - } - } - } - } - - return $testCases; + return self::mapPathsToRuntimeOs($testCases); }//end dataExcludePatterns() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php new file mode 100644 index 000000000..4d8f83d22 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php @@ -0,0 +1,268 @@ + + * @copyright 2023 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Filters; + +use PHP_CodeSniffer\Filters\GitModified; +use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; +use RecursiveArrayIterator; +use ReflectionMethod; + +/** + * Tests for the \PHP_CodeSniffer\Filters\GitModified class. + * + * @covers \PHP_CodeSniffer\Filters\GitModified + */ +final class GitModifiedTest extends AbstractFilterTestCase +{ + + + /** + * Test filtering a file list for excluded paths. + * + * @return void + */ + public function testFileNamePassesAsBasePathWillTranslateToDirname() + { + $rootFile = self::getBaseDir().'/autoload.php'; + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $constructorArgs = [ + $fakeDI, + $rootFile, + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitModified', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn(['autoload.php']); + + $this->assertSame([$rootFile], $this->getFilteredResultsAsArray($mockObj)); + + }//end testFileNamePassesAsBasePathWillTranslateToDirname() + + + /** + * Test filtering a file list for excluded paths. + * + * @param array $inputPaths List of file paths to be filtered. + * @param array $outputGitModified Simulated "git modified" output. + * @param array $expectedOutput Expected filtering result. + * + * @dataProvider dataAcceptOnlyGitModified + * + * @return void + */ + public function testAcceptOnlyGitModified($inputPaths, $outputGitModified, $expectedOutput) + { + $fakeDI = new RecursiveArrayIterator($inputPaths); + $constructorArgs = [ + $fakeDI, + self::getBaseDir(), + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitModified', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn($outputGitModified); + + $this->assertSame($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); + + }//end testAcceptOnlyGitModified() + + + /** + * Data provider. + * + * @see testAcceptOnlyGitModified + * + * @return array>> + */ + public static function dataAcceptOnlyGitModified() + { + $basedir = self::getBaseDir(); + $fakeFileList = self::getFakeFileList(); + + $testCases = [ + 'no files marked as git modified' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [], + 'expectedOutput' => [], + ], + + 'files marked as git modified which don\'t actually exist' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + 'src/WillNotExist.php', + 'src/WillNotExist.bak', + 'src/WillNotExist.orig', + ], + 'expectedOutput' => [], + ], + + 'single file marked as git modified - file in root dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + 'autoload.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + ], + ], + 'single file marked as git modified - file in sub dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, none valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + '.gitignore', + 'phpcs.xml.dist', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + ], + ], + + 'multiple files marked as git modified, only one file valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + '.gitignore', + 'src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Docs', + $basedir.'/src/Standards/Generic/Docs/Classes', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, multiple files valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + '.yamllint.yml', + 'autoload.php', + 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Sniffs', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + ], + ]; + + return $testCases; + + }//end dataAcceptOnlyGitModified() + + + /** + * Test filtering a file list for excluded paths. + * + * @param string $cmd Command to run. + * @param array $expected Expected return value. + * + * @dataProvider dataExecAlwaysReturnsArray + * + * @return void + */ + public function testExecAlwaysReturnsArray($cmd, $expected) + { + if (is_dir(__DIR__.'/../../../.git') === false) { + $this->markTestSkipped('Not a git repository'); + } + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $filter = new GitModified($fakeDI, '/', self::$config, self::$ruleset); + + $reflMethod = new ReflectionMethod($filter, 'exec'); + $reflMethod->setAccessible(true); + $result = $reflMethod->invoke($filter, $cmd); + + $this->assertSame($expected, $result); + + }//end testExecAlwaysReturnsArray() + + + /** + * Data provider. + * + * @see testExecAlwaysReturnsArray + * + * {@internal Missing: test with a command which yields a `false` return value. + * JRF: I've not managed to find a command which does so, let alone one, which then + * doesn't have side-effects of uncatchable output while running the tests.} + * + * @return array>> + */ + public static function dataExecAlwaysReturnsArray() + { + return [ + 'valid command which won\'t have any output unless files in the bin dir have been modified' => [ + // Largely using the command used in the filter, but only checking the bin dir. + // This should prevent the test unexpectedly failing during local development (in most cases). + 'cmd' => 'git ls-files -o -m --exclude-standard -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [], + ], + 'valid command which will have output' => [ + 'cmd' => 'git ls-files --exclude-standard -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [ + 'bin/phpcbf', + 'bin/phpcbf.bat', + 'bin/phpcs', + 'bin/phpcs.bat', + ], + ], + ]; + + }//end dataExecAlwaysReturnsArray() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php new file mode 100644 index 000000000..ce64794fb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php @@ -0,0 +1,268 @@ + + * @copyright 2023 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Filters; + +use PHP_CodeSniffer\Filters\GitStaged; +use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; +use RecursiveArrayIterator; +use ReflectionMethod; + +/** + * Tests for the \PHP_CodeSniffer\Filters\GitStaged class. + * + * @covers \PHP_CodeSniffer\Filters\GitStaged + */ +final class GitStagedTest extends AbstractFilterTestCase +{ + + + /** + * Test filtering a file list for excluded paths. + * + * @return void + */ + public function testFileNamePassesAsBasePathWillTranslateToDirname() + { + $rootFile = self::getBaseDir().'/autoload.php'; + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $constructorArgs = [ + $fakeDI, + $rootFile, + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitStaged', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn(['autoload.php']); + + $this->assertSame([$rootFile], $this->getFilteredResultsAsArray($mockObj)); + + }//end testFileNamePassesAsBasePathWillTranslateToDirname() + + + /** + * Test filtering a file list for excluded paths. + * + * @param array $inputPaths List of file paths to be filtered. + * @param array $outputGitStaged Simulated "git staged" output. + * @param array $expectedOutput Expected filtering result. + * + * @dataProvider dataAcceptOnlyGitStaged + * + * @return void + */ + public function testAcceptOnlyGitStaged($inputPaths, $outputGitStaged, $expectedOutput) + { + $fakeDI = new RecursiveArrayIterator($inputPaths); + $constructorArgs = [ + $fakeDI, + self::getBaseDir(), + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitStaged', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn($outputGitStaged); + + $this->assertSame($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); + + }//end testAcceptOnlyGitStaged() + + + /** + * Data provider. + * + * @see testAcceptOnlyGitStaged + * + * @return array>> + */ + public static function dataAcceptOnlyGitStaged() + { + $basedir = self::getBaseDir(); + $fakeFileList = self::getFakeFileList(); + + $testCases = [ + 'no files marked as git modified' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [], + 'expectedOutput' => [], + ], + + 'files marked as git modified which don\'t actually exist' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + 'src/WillNotExist.php', + 'src/WillNotExist.bak', + 'src/WillNotExist.orig', + ], + 'expectedOutput' => [], + ], + + 'single file marked as git modified - file in root dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + 'autoload.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + ], + ], + 'single file marked as git modified - file in sub dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, none valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + '.gitignore', + 'phpcs.xml.dist', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + ], + ], + + 'multiple files marked as git modified, only one file valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + '.gitignore', + 'src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Docs', + $basedir.'/src/Standards/Generic/Docs/Classes', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, multiple files valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + '.yamllint.yml', + 'autoload.php', + 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Sniffs', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + ], + ]; + + return $testCases; + + }//end dataAcceptOnlyGitStaged() + + + /** + * Test filtering a file list for excluded paths. + * + * @param string $cmd Command to run. + * @param array $expected Expected return value. + * + * @dataProvider dataExecAlwaysReturnsArray + * + * @return void + */ + public function testExecAlwaysReturnsArray($cmd, $expected) + { + if (is_dir(__DIR__.'/../../../.git') === false) { + $this->markTestSkipped('Not a git repository'); + } + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $filter = new GitStaged($fakeDI, '/', self::$config, self::$ruleset); + + $reflMethod = new ReflectionMethod($filter, 'exec'); + $reflMethod->setAccessible(true); + $result = $reflMethod->invoke($filter, $cmd); + + $this->assertSame($expected, $result); + + }//end testExecAlwaysReturnsArray() + + + /** + * Data provider. + * + * @see testExecAlwaysReturnsArray + * + * {@internal Missing: test with a command which yields a `false` return value. + * JRF: I've not managed to find a command which does so, let alone one, which then + * doesn't have side-effects of uncatchable output while running the tests.} + * + * @return array>> + */ + public static function dataExecAlwaysReturnsArray() + { + return [ + 'valid command which won\'t have any output unless files in the bin dir have been modified & staged' => [ + // Largely using the command used in the filter, but only checking the bin dir. + // This should prevent the test unexpectedly failing during local development (in most cases). + 'cmd' => 'git diff --cached --name-only -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [], + ], + 'valid command which will have output' => [ + 'cmd' => 'git ls-files --exclude-standard -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [ + 'bin/phpcbf', + 'bin/phpcbf.bat', + 'bin/phpcs', + 'bin/phpcs.bat', + ], + ], + ]; + + }//end dataExecAlwaysReturnsArray() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.diff b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.diff new file mode 100644 index 000000000..b9a217ed2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.diff @@ -0,0 +1,10 @@ +--- tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc ++++ PHP_CodeSniffer +@@ -5,7 +5,3 @@ + if ($var) { + echo 'This line is tab indented'; + } +- +- +- +- diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc new file mode 100644 index 000000000..2e65b2b50 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc @@ -0,0 +1,11 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Fixer; + +use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Tests for diff generation. + * + * Note: these tests are specifically about the Fixer::generateDiff() method and do not + * test running the fixer itself, nor generating a diff based on a fixer run. + * + * @covers PHP_CodeSniffer\Fixer::generateDiff + * @group Windows + */ +final class GenerateDiffTest extends TestCase +{ + + /** + * A \PHP_CodeSniffer\Files\File object to compare the files against. + * + * @var \PHP_CodeSniffer\Files\LocalFile + */ + private static $phpcsFile; + + + /** + * Initialize an \PHP_CodeSniffer\Files\File object with code. + * + * Things to take note of in the code snippet used for these tests: + * - Line endings are \n. + * - Tab indent. + * - Trailing whitespace. + * + * Also note that the Config object is deliberately created without a `tabWidth` setting to + * prevent doing tab replacement when parsing the file. This is to allow for testing a + * diff with tabs vs spaces (which wouldn't yield a diff if tabs had already been replaced). + * + * @beforeClass + * + * @return void + */ + public static function initializeFile() + { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + + self::$phpcsFile = new LocalFile(__DIR__.'/Fixtures/GenerateDiffTest.inc', $ruleset, $config); + self::$phpcsFile->parse(); + self::$phpcsFile->fixer->startFile(self::$phpcsFile); + + }//end initializeFile() + + + /** + * Test generating a diff on the file object itself. + * + * @return void + */ + public function testGenerateDiffNoFile() + { + $diff = self::$phpcsFile->fixer->generateDiff(null, false); + + $this->assertSame('', $diff); + + }//end testGenerateDiffNoFile() + + + /** + * Test generating a diff between a PHPCS File object and a file on disk. + * + * @param string $filePath The path to the file to compare the File object against. + * + * @dataProvider dataGenerateDiff + * + * @return void + */ + public function testGenerateDiff($filePath) + { + $diff = self::$phpcsFile->fixer->generateDiff($filePath, false); + + // Allow for the tests to pass on Windows too. + $diff = str_replace('--- tests\Core\Fixer/', '--- tests/Core/Fixer/', $diff); + + $expectedDiffFile = str_replace('.inc', '.diff', $filePath); + + $this->assertStringEqualsFile($expectedDiffFile, $diff); + + }//end testGenerateDiff() + + + /** + * Data provider. + * + * @see testGenerateDiff() + * + * @return array> + */ + public static function dataGenerateDiff() + { + return [ + 'no difference' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-NoDiff.inc', + ], + 'line removed' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-LineRemoved.inc', + ], + 'line added' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-LineAdded.inc', + ], + 'var name changed' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-VarNameChanged.inc', + ], + 'trailing whitespace removed' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-NoTrailingWhitespace.inc', + ], + 'tab replaced with spaces' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-TabsToSpaces.inc', + ], + 'blank lines at start of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-BlankLinesAtStart.inc', + ], + 'whitespace diff at start of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-WhiteSpaceAtStart.inc', + ], + 'blank lines at end of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc', + ], + 'whitespace diff at end of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-WhiteSpaceAtEnd.inc', + ], + ]; + + }//end dataGenerateDiff() + + + /** + * Test generating a diff between a PHPCS File object and a file on disk and colourizing the output. + * + * @return void + */ + public function testGenerateDiffColoured() + { + $expected = "\033[31m--- tests/Core/Fixer/Fixtures/GenerateDiffTest-VarNameChanged.inc\033[0m".PHP_EOL; + $expected .= "\033[32m+++ PHP_CodeSniffer\033[0m".PHP_EOL; + $expected .= '@@ -1,7 +1,7 @@'.PHP_EOL; + $expected .= ' fixer->generateDiff($filePath); + + // Allow for the tests to pass on Windows too. + $diff = str_replace('--- tests\Core\Fixer/', '--- tests/Core/Fixer/', $diff); + + $this->assertSame($expected, $diff); + + }//end testGenerateDiffColoured() + + + /** + * Test generating a diff between a PHPCS File object using *nix line endings and a file on disk + * using Windows line endings. + * + * The point of this test is to verify that all lines are marked as having a difference. + * The actual lines endings used in the diff shown to the end-user are not relevant for this + * test. + * As the "diff" command is finicky with what type of line endings are used when the only + * difference on a line is the line ending, the test normalizes the line endings of the + * received diff before testing it. + * + * @return void + */ + public function testGenerateDiffDifferentLineEndings() + { + // By the looks of it, if the only diff between two files is line endings, the + // diff generated by the *nix "diff" command will always contain *nix line endings. + $expected = '--- tests/Core/Fixer/Fixtures/GenerateDiffTest-WindowsLineEndings.inc'."\n"; + $expected .= '+++ PHP_CodeSniffer'."\n"; + $expected .= '@@ -1,7 +1,7 @@'."\n"; + $expected .= '-fixer->generateDiff($filePath, false); + + // Allow for the tests to pass on Windows too. + $diff = str_replace('--- tests\Core\Fixer/', '--- tests/Core/Fixer/', $diff); + + // Normalize line endings of the diff. + $diff = preg_replace('`\R`', "\n", $diff); + + $this->assertSame($expected, $diff); + + }//end testGenerateDiffDifferentLineEndings() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AllValidDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AllValidDocsTest.xml new file mode 100644 index 000000000..71a0c7f7a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AllValidDocsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml new file mode 100644 index 000000000..0e66fabc9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html new file mode 100644 index 000000000..a51ad92a8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+
+

This is a standard block.

+

Code Comparison, blank lines §

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

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

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

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

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

GeneratorTest Coding Standards

+

Code Comparison, block length §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Code Comparison, char encoding §

+

This is a standard block.

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

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

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

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

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

GeneratorTest Coding Standards

+

Code Comparison, line length §

+

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

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

GeneratorTest Coding Standards

+

Code Title, line wrapping §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Code Title, whitespace handling §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

lowercase title §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

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

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Documentation Title PCRE Fallback §

+

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

+

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

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

GeneratorTest Coding Standards

+

Table of Contents

+ +

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

+

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

+

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

+

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

+

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

+

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

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

GeneratorTest Coding Standards

+

Code Comparison, mismatched code blocks §

+

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

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

GeneratorTest Coding Standards

+

Code Comparison, missing code element §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Code Comparison, no code §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Code Comparison, no content §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Code Comparison, one empty code element §

+

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

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

GeneratorTest Coding Standards

+

Code Comparison, two empty code elements §

+

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

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

GeneratorTest Coding Standards

+

Code Title, empty §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Code Title, missing §

+

This is a standard block.

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

GeneratorTest Coding Standards

+

Documentation Title Empty §

+

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

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

GeneratorTest Coding Standards

+

Documentation Title Missing §

+

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

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

GeneratorTest Coding Standards

+

Standard Element, no content §

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

GeneratorTest Coding Standards

+

One Standard Block, No Code §

+

Documentation contains one standard block and no code comparison.

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

GeneratorTest Coding Standards

+

Standard Element, blank line handling §

+

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

+

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

+

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

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

GeneratorTest Coding Standards

+

Standard Element, handling of HTML tags §

+

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

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

GeneratorTest Coding Standards

+

Standard Element, indentation should be ignored §

+

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

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

GeneratorTest Coding Standards

+

Standard Element, line wrapping handling §

+

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

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

GeneratorTest Coding Standards

+

Table of Contents

+ +

Code Comparison Only, Missing Standard Block §

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

One Standard Block, Code Comparison §

+

Documentation contains one standard block and one code comparison.

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

One Standard Block, No Code §

+

Documentation contains one standard block and no code comparison.

+

One Standard Block, Two Code Comparisons §

+

Documentation contains one standard block and two code comparisons.

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

Two Standard Blocks, No Code §

+

This is standard block one.

+

This is standard block two.

+

Two Standard Blocks, One Code Comparison §

+

This is standard block one.

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

This is standard block two.

+

Two Standard Blocks, Three Code Comparisons §

+

This is standard block one.

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

This is standard block two.

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

GeneratorTest Coding Standards

+

One element correct, one element wrong level §

+

This is a standard block at the correct level.

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

GeneratorTest Coding Standards

+

Superfluous code element §

+

This is a standard block.

+ + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
$valid = true;$invalid = true;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md new file mode 100644 index 000000000..f6cdad946 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Superfluous code element + +This is a standard block. + + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
+ + $valid = true; + + + + $invalid = true; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt new file mode 100644 index 000000000..1307eebfd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt @@ -0,0 +1,13 @@ + +----------------------------------------------------------- +| GENERATORTEST CODING STANDARD: SUPERFLUOUS CODE ELEMENT | +----------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Checking handling of blank lines. | Invalid: Checking handling of blank lines. | +---------------------------------------------------------------------------------------------------- +| $valid = true; | $invalid = true; | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php new file mode 100644 index 000000000..8b737fb7c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php @@ -0,0 +1,40 @@ +Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION# + +'; + + // Use the correct line endings based on the OS. + return str_replace("\n", PHP_EOL, $output).PHP_EOL; + } + + /** + * Retrieve the _real_ footer of the HTML page. + * + * @return string + */ + public function getRealFooter() + { + return parent::getFormattedFooter(); + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php new file mode 100644 index 000000000..e783f7dda --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php @@ -0,0 +1,38 @@ +getTitle($doc), PHP_EOL; + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml new file mode 100644 index 000000000..bcaf82bbb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml new file mode 100644 index 000000000..c479a7fd0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml @@ -0,0 +1,35 @@ + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml new file mode 100644 index 000000000..c366553f3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml @@ -0,0 +1,42 @@ + + + + + + + $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + + +// The above PHP tag is specifically testing +// handling of that in generated HTML doc. + +// Now let's also check the handling of +// comparison operators in code samples +// in combination with "em" tags. +$a = $b < $c; +$d = $e > $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml new file mode 100644 index 000000000..b4431ea84 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml @@ -0,0 +1,25 @@ + + + + + + + Countable, Serializable +{ +} + ]]> + + + foobar($param1, $param2) {} +} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml new file mode 100644 index 000000000..b773f7a88 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml new file mode 100644 index 000000000..282972025 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml new file mode 100644 index 000000000..a4078e3de --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml new file mode 100644 index 000000000..244892764 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml new file mode 100644 index 000000000..1aa3849bd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml new file mode 100644 index 000000000..4edae6918 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml new file mode 100644 index 000000000..43956e3fc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml new file mode 100644 index 000000000..43956e3fc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml new file mode 100644 index 000000000..10c47bf46 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml new file mode 100644 index 000000000..3e34c3f9f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml @@ -0,0 +1,8 @@ + + + tags in standard descriptions is allowed and their handling should be safeguarded. + Other tags, like link, bold, are not allowed and will be encoded for display when the HTML or Markdown report is used. + ]]> + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml new file mode 100644 index 000000000..b2ec6c5e3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml new file mode 100644 index 000000000..66bbb9627 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml new file mode 100644 index 000000000..d0cfff411 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml new file mode 100644 index 000000000..999901ebb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml new file mode 100644 index 000000000..54b50ff8d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml new file mode 100644 index 000000000..0dfb12fa0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml new file mode 100644 index 000000000..b40674413 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml new file mode 100644 index 000000000..e6cb07145 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml new file mode 100644 index 000000000..034bdf2fd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml new file mode 100644 index 000000000..89599dd2b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml new file mode 100644 index 000000000..c3ab071d1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml new file mode 100644 index 000000000..974071d9f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml new file mode 100644 index 000000000..e6934706a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml @@ -0,0 +1,15 @@ + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml new file mode 100644 index 000000000..83afee8e8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml new file mode 100644 index 000000000..ca8290f1b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml new file mode 100644 index 000000000..c2af9098a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml @@ -0,0 +1,14 @@ + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml new file mode 100644 index 000000000..c3ce35cd7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml new file mode 100644 index 000000000..fc014949e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml new file mode 100644 index 000000000..19559e672 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml @@ -0,0 +1,31 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml new file mode 100644 index 000000000..f5f621ecd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml new file mode 100644 index 000000000..a5b3a3216 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml @@ -0,0 +1,24 @@ + + + + + + + Code {} + ]]> + + + Comparison {} + ]]> + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml new file mode 100644 index 000000000..540ac7eaf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml @@ -0,0 +1,48 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml new file mode 100644 index 000000000..68519dd2b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml new file mode 100644 index 000000000..6c1dd164a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml new file mode 100644 index 000000000..333786a33 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml new file mode 100644 index 000000000..c9ec3227f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php new file mode 100644 index 000000000..1e56bf9cf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php @@ -0,0 +1,12 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php new file mode 100644 index 000000000..8fb0ee251 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php @@ -0,0 +1,227 @@ + $expected The expected list of found docs. + * + * @dataProvider dataConstructor + * + * @return void + */ + public function testConstructor($standard, array $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MockGenerator($ruleset); + $this->assertSame($expected, $generator->docFiles); + + }//end testConstructor() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataConstructor() + { + $pathToDocsInFixture = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'StandardWithDocs'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => [], + ], + 'Standard with an invalid doc file' => [ + 'standard' => __DIR__.'/NoValidDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoDocumentationElementStandard.xml', + ], + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + ], + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoContentStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneCodeComparisonNoStandardStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockTwoCodeComparisonsStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksOneCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksThreeCodeComparisonsStandard.xml', + ], + ], + ]; + + }//end dataConstructor() + + + /** + * Verify that an XML doc which isn't valid documentation yields an Exception to warn devs. + * + * This should not be hidden via defensive coding! + * + * @return void + */ + public function testGeneratingInvalidDocsResultsInException() + { + // Set up the ruleset. + $standard = __DIR__.'/NoValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + if (PHP_VERSION_ID >= 80000) { + $exception = 'TypeError'; + $message = 'processSniff(): Argument #1 ($doc) must be of type DOMNode, null given'; + } else if (PHP_VERSION_ID >= 70000) { + $exception = 'TypeError'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } else { + $exception = 'PHPUnit_Framework_Error'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } + + if (method_exists($this, 'expectExceptionMessage') === true) { + // PHPUnit 5.2.0+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // Ancient PHPUnit. + $this->setExpectedException($exception, $message); + } + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingInvalidDocsResultsInException() + + + /** + * Verify the wiring for the generate() function. + * + * @param string $standard The standard to use for the test. + * @param string $expected The expected function output. + * + * @dataProvider dataGeneratingDocs + * + * @return void + */ + public function testGeneratingDocs($standard, $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $this->expectOutputString($expected); + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataGeneratingDocs() + { + $multidocExpected = []; + $multidocExpected[] = 'No Content'; + $multidocExpected[] = 'Code Comparison Only, Missing Standard Block'; + $multidocExpected[] = 'One Standard Block, Code Comparison'; + $multidocExpected[] = 'One Standard Block, No Code'; + $multidocExpected[] = 'One Standard Block, Two Code Comparisons'; + $multidocExpected[] = 'Two Standard Blocks, No Code'; + $multidocExpected[] = 'Two Standard Blocks, One Code Comparison'; + $multidocExpected[] = 'Two Standard Blocks, Three Code Comparisons'; + $multidocExpected = implode(PHP_EOL, $multidocExpected).PHP_EOL; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => '', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => 'One Standard Block, No Code'.PHP_EOL, + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => $multidocExpected, + ], + ]; + + }//end dataGeneratingDocs() + + + /** + * Verify that if the `` title is missing, it will fallback to the file name + * and split the CamelCaps name correctly. + * + * @return void + */ + public function testGetTitleFallbackToFilename() + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $sniffs = 'StandardWithDocs.Content.DocumentationTitlePCREFallback'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + // Make the test OS independent. + $this->expectOutputString('Documentation Title PCRE Fallback'.PHP_EOL); + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGetTitleFallbackToFilename() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php new file mode 100644 index 000000000..a8ac84a8a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php @@ -0,0 +1,366 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.html', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.html', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.html', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.html', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.html', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.html', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.html', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.html', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.html', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.html', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.html', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.html', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.html', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.html', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.html', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.html', + ], + ]; + + }//end dataDocSpecifics() + + + /** + * Test anchor links in the generated docs are slugified and unique. + * + * @return void + */ + public function testAnchorLinks() + { + // Set up the ruleset. + $standard = __DIR__.'/AnchorLinksTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $pathToExpected = __DIR__.'/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html'; + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testAnchorLinks() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^
'; + $regex .= 'Documentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+'; + $regex .= '
\R \R\R$`'; + + $generator = new HTMLDouble($ruleset); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } + + }//end testFooter() + + + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->getRealFooter(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->getRealFooter(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php new file mode 100644 index 000000000..6bc2c4fba --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php @@ -0,0 +1,338 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.md', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.md', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.md', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.md', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.md', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.md', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.md', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.md', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.md', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.md', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.md', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.md', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.md', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.md', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.md', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.md', + ], + ]; + + }//end dataDocSpecifics() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^\RDocumentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by \[PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+\]\(https://github\.com/PHPCSStandards/PHP_CodeSniffer\)\R$`'; + + $generator = new MarkdownDouble($ruleset); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } + + }//end testFooter() + + + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->getRealFooter(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->getRealFooter(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml new file mode 100644 index 000000000..51df8395c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml new file mode 100644 index 000000000..94dda4e71 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml new file mode 100644 index 000000000..83ca4384e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml new file mode 100644 index 000000000..45811bee6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php new file mode 100644 index 000000000..90bb7bf89 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php @@ -0,0 +1,245 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.txt', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.txt', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.txt', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.txt', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.txt', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.txt', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.txt', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.txt', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.txt', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.txt', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.txt', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.txt', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.txt', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.txt', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.txt', + ], + ]; + + }//end dataDocSpecifics() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php new file mode 100644 index 000000000..41c639443 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php @@ -0,0 +1,115 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHPUnit\Framework\TestCase; + +abstract class AbstractRulesetTestCase extends TestCase +{ + + /** + * The fully qualified name of the PHPCS runtime exception class. + * + * @var string + */ + const RUNTIME_EXCEPTION = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + + + /** + * Asserts that an object has a specified property in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectHasProperty') === true) { + $this->assertObjectHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectHasProperty() + + + /** + * Asserts that an object does not have a specified property + * in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectNotHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectNotHasProperty') === true) { + $this->assertObjectNotHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectNotHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectNotHasProperty() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException with a certain message + * in a PHPUnit cross-version compatible manner. + * + * @param string $message The expected exception message. + * + * @return void + */ + protected function expectRuntimeExceptionMessage($message) + { + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException(self::RUNTIME_EXCEPTION, $message); + } + + }//end expectRuntimeExceptionMessage() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException which matches a regex patten + * in a PHPUnit cross-version compatible manner. + * + * @param string $regex The regex which should match. + * + * @return void + */ + protected function expectRuntimeExceptionRegex($regex) + { + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp(self::RUNTIME_EXCEPTION, $regex); + } + + }//end expectRuntimeExceptionRegex() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml new file mode 100644 index 000000000..77ae02580 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml @@ -0,0 +1,6 @@ + + + + . + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php new file mode 100644 index 000000000..eaea6c239 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Autoload; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::__construct() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::__construct + */ +final class ConstructorTest extends AbstractRulesetTestCase +{ + + + /** + * Test setting the ruleset name. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param string $expected The expected set ruleset name. + * + * @dataProvider dataHandlingStandardsPassedViaCLI + * + * @return void + */ + public function testHandlingStandardsPassedViaCLI($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + $ruleset = new Ruleset($config); + + $this->assertSame($expected, $ruleset->name); + + }//end testHandlingStandardsPassedViaCLI() + + + /** + * Data provider. + * + * @see testHandlingStandardsPassedViaCLI() + * + * @return array>> + */ + public static function dataHandlingStandardsPassedViaCLI() + { + return [ + 'Single standard passed' => [ + 'cliArgs' => ['--standard=PSR1'], + 'expected' => 'PSR1', + ], + 'Multiple standards passed' => [ + 'cliArgs' => ['--standard=PSR1,Zend'], + 'expected' => 'PSR1, Zend', + ], + 'Absolute path to standard directory passed' => [ + 'cliArgs' => [ + '--standard='.__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard', + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => 'TestStandard', + ], + ]; + + }//end dataHandlingStandardsPassedViaCLI() + + + /** + * Verify that standards are registered with the Autoloader. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param array $expected Minimum set of standards expected to be registered with the autoloader. + * + * @dataProvider dataStandardsAreRegisteredWithAutoloader + * + * @return void + */ + public function testStandardsAreRegisteredWithAutoloader($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + new Ruleset($config); + + $autoloadPaths = Autoload::getSearchPaths(); + + // Note: doing a full comparison of the Autoloader registered standards would make this test unstable + // as the `CodeSniffer.conf` of the user running the tests could interfer if they have additional + // external standards registered. + // Also note that `--runtime-set` is being used to set `installed_paths` to prevent making any changes to + // the `CodeSniffer.conf` file of the user running the tests. + foreach ($expected as $path => $namespacedStandardName) { + $this->assertArrayHasKey($path, $autoloadPaths, "Path $path has not been registered with the autoloader"); + $this->assertSame($namespacedStandardName, $autoloadPaths[$path], 'Expected (namespaced) standard name does not match'); + } + + }//end testStandardsAreRegisteredWithAutoloader() + + + /** + * Data provider. + * + * @see testStandardsAreRegisteredWithAutoloader() + * + * @return array>> + */ + public static function dataStandardsAreRegisteredWithAutoloader() + { + $basePath = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + $defaultPaths = [ + $basePath.'MySource' => 'MySource', + $basePath.'PEAR' => 'PEAR', + $basePath.'PSR1' => 'PSR1', + $basePath.'PSR12' => 'PSR12', + $basePath.'PSR2' => 'PSR2', + $basePath.'Squiz' => 'Squiz', + $basePath.'Zend' => 'Zend', + ]; + + $data = [ + 'Default standards' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--runtime-set installed_paths .', + ], + 'expected' => $defaultPaths, + ], + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'DirectoryExpansion'; + $extraInstalledPath .= DIRECTORY_SEPARATOR.'.hiddenAbove'.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'MyStandard'; + $data['Additional non-namespaced standard'] = [ + 'cliArgs' => [ + '--standard=MyStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'MyStandard']), + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard'; + $data['Additional namespaced standard'] = [ + 'cliArgs' => [ + '--standard=TestStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'Fixtures\TestStandard']), + ]; + + return $data; + + }//end dataStandardsAreRegisteredWithAutoloader() + + + /** + * Verify handling of sniff restrictions in combination with the caching setting. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param bool $cache Whether to turn the cache on or off. + * @param array $expected Sniffs which are expected to have been registered. + * + * @dataProvider dataCachingVersusRestrictions + * + * @return void + */ + public function testCachingVersusRestrictions($cliArgs, $cache, $expected) + { + $config = new ConfigDouble($cliArgs); + + // Overrule the cache setting (which is being ignored in the Config when the tests are running). + $config->cache = $cache; + + $ruleset = new Ruleset($config); + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testCachingVersusRestrictions() + + + /** + * Data provider. + * + * Note: the test cases only use `--exclude` to restrict, + * + * @see testCachingVersusRestrictions() + * + * @return array>> + */ + public static function dataCachingVersusRestrictions() + { + $completeSet = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + return [ + 'No restrictions, cache off' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => false, + 'expected' => $completeSet, + ], + 'Has exclusions, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ], + ], + 'Has sniff selection, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--sniffs=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + ], + ], + 'No restrictions, cache on' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => true, + 'expected' => $completeSet, + ], + 'Has exclusions, cache on' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowAlternativePHPTags,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects', + ], + 'cache' => true, + 'expected' => $completeSet, + ], + + /* + * "Has sniff selection, cache on" case cannot be tested due to the `Ruleset` class + * containing special handling of sniff selection when the tests are running. + */ + + ]; + + }//end dataCachingVersusRestrictions() + + + /** + * Test an exception is thrown when no sniffs have been registered via the ruleset. + * + * @return void + */ + public function testNoSniffsRegisteredException() + { + $standard = __DIR__.'/ConstructorNoSniffsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testNoSniffsRegisteredException() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php new file mode 100644 index 000000000..446bbfbcf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php @@ -0,0 +1,306 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use PHP_CodeSniffer\Util\MessageCollector; +use ReflectionMethod; +use ReflectionProperty; + +/** + * Test error handling for the Ruleset. + * + * Note: this is purely a unit test of the `displayCachedMessages()` method. + * The errors themselves are mocked. + * + * @covers \PHP_CodeSniffer\Ruleset::displayCachedMessages + */ +final class DisplayCachedMessagesTest extends AbstractRulesetTestCase +{ + + + /** + * Test that no exception nor output is generated when there are no cached messsages. + * + * @return void + */ + public function testDisplayCachedMessagesStaysSilentWithoutErrors() + { + $ruleset = $this->getPlainRuleset(); + + $this->expectOutputString(''); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testDisplayCachedMessagesStaysSilentWithoutErrors() + + + /** + * Verify that blocking errors encountered while loading the ruleset(s) result in an exception being thrown. + * + * @param array $messages The messages encountered. + * @param string $expected The expected function output to screen (via an internally handled exception). + * + * @dataProvider dataBlockingErrorsAreDisplayedViaAnException + * + * @return void + */ + public function testBlockingErrorsAreDisplayedViaAnException($messages, $expected) + { + $ruleset = $this->getPlainRuleset(); + $this->mockCachedMessages($ruleset, $messages); + + $this->expectRuntimeExceptionMessage($expected); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testBlockingErrorsAreDisplayedViaAnException() + + + /** + * Data provider. + * + * @see testBlockingErrorsAreDisplayedViaAnException() + * + * @return array>> + */ + public static function dataBlockingErrorsAreDisplayedViaAnException() + { + return [ + 'One error' => [ + 'messages' => ['This is a serious blocking issue' => MessageCollector::ERROR], + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL.PHP_EOL, + ], + 'Multiple blocking errors' => [ + 'messages' => [ + 'This is a serious blocking issue' => MessageCollector::ERROR, + 'And here is another one' => MessageCollector::ERROR, + 'OMG, why do you think that would work ?' => MessageCollector::ERROR, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL + . 'ERROR: And here is another one'.PHP_EOL + . 'ERROR: OMG, why do you think that would work ?'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + 'Mix of blocking and non-blocking errors' => [ + 'messages' => [ + 'This is a serious blocking issue' => MessageCollector::ERROR, + 'Something something deprecated and will be removed in v x.x.x' => MessageCollector::DEPRECATED, + 'Careful, this may not be correct' => MessageCollector::NOTICE, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL + . 'NOTICE: Careful, this may not be correct'.PHP_EOL + . 'DEPRECATED: Something something deprecated and will be removed in v x.x.x'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + ]; + + }//end dataBlockingErrorsAreDisplayedViaAnException() + + + /** + * Test display of non-blocking messages encountered while loading the ruleset(s). + * + * @param array $messages The messages encountered. + * @param string $expected The expected function output to screen. + * + * @dataProvider dataNonBlockingErrorsGenerateOutput + * + * @return void + */ + public function testNonBlockingErrorsGenerateOutput($messages, $expected) + { + $ruleset = $this->getPlainRuleset(); + $this->mockCachedMessages($ruleset, $messages); + + $this->expectOutputString($expected); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testNonBlockingErrorsGenerateOutput() + + + /** + * Data provider. + * + * @see testNonBlockingErrorsGenerateOutput() + * + * @return array>> + */ + public static function dataNonBlockingErrorsGenerateOutput() + { + return [ + 'One deprecation' => [ + 'messages' => ['My deprecation message' => MessageCollector::DEPRECATED], + 'expected' => 'DEPRECATED: My deprecation message'.PHP_EOL.PHP_EOL, + ], + 'One notice' => [ + 'messages' => ['My notice message' => MessageCollector::NOTICE], + 'expected' => 'NOTICE: My notice message'.PHP_EOL.PHP_EOL, + ], + 'One warning' => [ + 'messages' => ['My warning message' => MessageCollector::WARNING], + 'expected' => 'WARNING: My warning message'.PHP_EOL.PHP_EOL, + ], + 'Multiple non-blocking errors' => [ + 'messages' => [ + 'Something something deprecated and will be removed in v x.x.x' => MessageCollector::DEPRECATED, + 'Something is not supported and support may be removed' => MessageCollector::WARNING, + 'Some other deprecation notice' => MessageCollector::DEPRECATED, + 'Careful, this may not be correct' => MessageCollector::NOTICE, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'WARNING: Something is not supported and support may be removed'.PHP_EOL + .'NOTICE: Careful, this may not be correct'.PHP_EOL + .'DEPRECATED: Something something deprecated and will be removed in v x.x.x'.PHP_EOL + .'DEPRECATED: Some other deprecation notice'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + ]; + + }//end dataNonBlockingErrorsGenerateOutput() + + + /** + * Test that blocking errors will always show, independently of specific command-line options being used. + * + * @param array $configArgs Arguments to pass to the Config. + * + * @dataProvider dataSelectiveDisplayOfMessages + * + * @return void + */ + public function testBlockingErrorsAlwaysShow($configArgs) + { + $config = new ConfigDouble($configArgs); + $ruleset = new Ruleset($config); + + $message = 'Some serious error'; + $errors = [$message => MessageCollector::ERROR]; + $this->mockCachedMessages($ruleset, $errors); + + $this->expectRuntimeExceptionMessage('ERROR: '.$message.PHP_EOL); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testBlockingErrorsAlwaysShow() + + + /** + * Test that non-blocking messsages will not show when specific command-line options are being used. + * + * @param array $configArgs Arguments to pass to the Config. + * + * @dataProvider dataSelectiveDisplayOfMessages + * + * @return void + */ + public function testNonBlockingErrorsDoNotShowUnderSpecificCircumstances($configArgs) + { + $config = new ConfigDouble($configArgs); + $ruleset = new Ruleset($config); + $this->mockCachedMessages($ruleset, ['Deprecation notice' => MessageCollector::DEPRECATED]); + + $this->expectOutputString(''); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testNonBlockingErrorsDoNotShowUnderSpecificCircumstances() + + + /** + * Data provider. + * + * @see testBlockingErrorsAlwaysShow() + * @see testNonBlockingErrorsDoNotShow() + * + * @return array>> + */ + public static function dataSelectiveDisplayOfMessages() + { + return [ + 'Explain mode' => [ + 'configArgs' => ['-e'], + ], + 'Quiet mode' => [ + 'configArgs' => ['-q'], + ], + 'Documentation is requested' => [ + 'configArgs' => ['--generator=text'], + ], + ]; + + }//end dataSelectiveDisplayOfMessages() + + + /** + * Test Helper. + * + * @return \PHP_CodeSniffer\Ruleset + */ + private function getPlainRuleset() + { + static $ruleset; + + if (isset($ruleset) === false) { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + } + + return $ruleset; + + }//end getPlainRuleset() + + + /** + * Add mock messages to the message cache. + * + * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset object. + * @param array $messages The messages to add to the message cache. + * + * @return void + */ + private function mockCachedMessages(Ruleset $ruleset, $messages) + { + $reflProperty = new ReflectionProperty($ruleset, 'msgCache'); + $reflProperty->setAccessible(true); + + $msgCache = $reflProperty->getValue($ruleset); + foreach ($messages as $msg => $type) { + $msgCache->add($msg, $type); + } + + $reflProperty->setAccessible(false); + + }//end mockCachedMessages() + + + /** + * Invoke the display of the cached messages. + * + * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset object. + * + * @return void + */ + private function invokeDisplayCachedMessages(Ruleset $ruleset) + { + $reflMethod = new ReflectionMethod($ruleset, 'displayCachedMessages'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($ruleset); + $reflMethod->setAccessible(false); + + }//end invokeDisplayCachedMessages() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml new file mode 100644 index 000000000..7b2222301 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml new file mode 100644 index 000000000..1080c769f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml new file mode 100644 index 000000000..803c848de --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php new file mode 100644 index 000000000..10a4dd981 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php @@ -0,0 +1,121 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test home path handling in the Ruleset::expandRulesetReference() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceHomePathTest extends AbstractRulesetTestCase +{ + + /** + * Original value of the user's home path environment variable. + * + * @var string|false Path or false is the `HOME` environment variable is not available. + */ + private static $homepath = false; + + + /** + * Store the user's home path. + * + * @beforeClass + * + * @return void + */ + public static function storeHomePath() + { + self::$homepath = getenv('HOME'); + + }//end storeHomePath() + + + /** + * Restore the user's home path environment variable in case the test changed it or created it. + * + * @afterClass + * + * @return void + */ + public static function restoreHomePath() + { + if (is_string(self::$homepath) === true) { + putenv('HOME='.self::$homepath); + } else { + // Remove the environment variable as it didn't exist before. + putenv('HOME'); + } + + }//end restoreHomePath() + + + /** + * Set the home path to an alternative location. + * + * @before + * + * @return void + */ + protected function setHomePath() + { + $fakeHomePath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'FakeHomePath'; + putenv("HOME=$fakeHomePath"); + + }//end setHomePath() + + + /** + * Verify that a sniff reference with the magic "home path" placeholder gets expanded correctly + * and finds sniffs if the path exists underneath the "home path". + * + * @return void + */ + public function testHomePathRefGetsExpandedAndFindsSniff() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceHomePathTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['MyStandard.Category.Valid' => 'FakeHomePath\\MyStandard\\Sniffs\\Category\\ValidSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testHomePathRefGetsExpandedAndFindsSniff() + + + /** + * Verify that a sniff reference with the magic "home path" placeholder gets expanded correctly + * and still fails to find sniffs if the path doesn't exists underneath the "home path". + * + * @return void + */ + public function testHomePathRefGetsExpandedAndThrowsExceptionWhenPathIsInvalid() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceHomePathFailTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $exceptionMessage = 'ERROR: Referenced sniff "~/src/MyStandard/Sniffs/DoesntExist/" does not exist.'.PHP_EOL; + $exceptionMessage .= 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($exceptionMessage); + + new Ruleset($config); + + }//end testHomePathRefGetsExpandedAndThrowsExceptionWhenPathIsInvalid() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml new file mode 100644 index 000000000..8d39a2693 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml new file mode 100644 index 000000000..9398e402b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml @@ -0,0 +1,15 @@ + + + + + + + 0 + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml new file mode 100644 index 000000000..0493e253c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php new file mode 100644 index 000000000..edac7490d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php @@ -0,0 +1,66 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of "internal" references in the Ruleset::expandRulesetReference() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceInternalTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that a ruleset reference starting with "Internal." (including the dot) doesn't cause any sniffs to be registered. + * + * @return void + */ + public function testInternalRefDoesNotGetExpanded() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceInternalIgnoreTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\BacktickOperatorSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testInternalRefDoesNotGetExpanded() + + + /** + * While definitely not recommended, including a standard named "Internal", _does_ allow for sniffs to be registered. + * + * Note: customizations (exclusions/property setting etc) for individual sniffs may not always be handled correctly, + * which is why naming a standard "Internal" is definitely not recommended. + * + * @return void + */ + public function testInternalStandardDoesGetExpanded() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceInternalStandardTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Internal.Valid.Valid' => 'Fixtures\\Internal\\Sniffs\\Valid\\ValidSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testInternalStandardDoesGetExpanded() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml new file mode 100644 index 000000000..f864f3513 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml new file mode 100644 index 000000000..49814db7b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml new file mode 100644 index 000000000..439fe9a67 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml new file mode 100644 index 000000000..801ead6dd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml new file mode 100644 index 000000000..c7d95e431 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php new file mode 100644 index 000000000..284bdf7fb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php @@ -0,0 +1,134 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::expandRulesetReference() method not covered by other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceTest extends AbstractRulesetTestCase +{ + + + /** + * Test handling of path references relative to the originally included ruleset. + * + * @return void + */ + public function testRulesetRelativePathReferences() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = [ + 'ExternalA.CheckSomething.Valid' => 'Fixtures\\ExternalA\\Sniffs\\CheckSomething\\ValidSniff', + 'TestStandard.ValidSniffs.RegisterEmptyArray' => 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff', + 'ExternalB.CheckMore.Valid' => 'Fixtures\\ExternalB\\Sniffs\\CheckMore\\ValidSniff', + ]; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testRulesetRelativePathReferences() + + + /** + * Test that an exception is thrown if a ruleset contains an unresolvable reference. + * + * @param string $standard The standard to use for the test. + * @param string $replacement The reference which will be used in the exception message. + * + * @dataProvider dataUnresolvableReferenceThrowsException + * + * @return void + */ + public function testUnresolvableReferenceThrowsException($standard, $replacement) + { + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + + $exceptionMessage = 'ERROR: Referenced sniff "%s" does not exist.'.PHP_EOL; + $exceptionMessage .= 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage(sprintf($exceptionMessage, $replacement)); + + new Ruleset($config); + + }//end testUnresolvableReferenceThrowsException() + + + /** + * Data provider. + * + * @see testUnresolvableReferenceThrowsException() + * + * @return array> + */ + public static function dataUnresolvableReferenceThrowsException() + { + $data = [ + 'Referencing a non-existent XML file' => [ + 'standard' => 'ExpandRulesetReferenceMissingFileTest.xml', + 'replacement' => './MissingFile.xml', + ], + 'Referencing an invalid directory starting with "~"' => [ + 'standard' => 'ExpandRulesetReferenceInvalidHomePathRefTest.xml', + 'replacement' => '~/src/Standards/Squiz/Sniffs/Files/', + ], + 'Referencing an unknown standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownStandardTest.xml', + 'replacement' => 'UnknownStandard', + ], + 'Referencing a non-existent category in a known standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownCategoryTest.xml', + 'replacement' => 'TestStandard.UnknownCategory', + ], + 'Referencing a non-existent sniff in a known standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownSniffTest.xml', + 'replacement' => 'TestStandard.InvalidSniffs.UnknownRule', + ], + 'Referencing an invalid error code - no standard name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode1Test.xml', + 'replacement' => '.Invalid.Undetermined.Found', + ], + 'Referencing an invalid error code - no category name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode2Test.xml', + 'replacement' => 'Standard..Undetermined.Found', + ], + 'Referencing an invalid error code - no sniff name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode3Test.xml', + 'replacement' => 'Standard.Invalid..Found', + ], + ]; + + // Add tests which are only relevant for case-sensitive OSes. + if (stripos(PHP_OS, 'WIN') === false) { + $data['Referencing an existing sniff, but there is a case mismatch (OS-dependent) [1]'] = [ + 'standard' => 'ExpandRulesetReferenceCaseMismatch1Test.xml', + 'replacement' => 'psr12.functions.nullabletypedeclaration', + ]; + $data['Referencing an existing sniff, but there is a case mismatch (OS-dependent) [2]'] = [ + 'standard' => 'ExpandRulesetReferenceCaseMismatch2Test.xml', + 'replacement' => 'PSR12.Functions.ReturntypeDeclaration', + ]; + } + + return $data; + + }//end dataUnresolvableReferenceThrowsException() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml new file mode 100644 index 000000000..aaa23759e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml new file mode 100644 index 000000000..26f8c8491 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml new file mode 100644 index 000000000..8b9b3ad19 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml new file mode 100644 index 000000000..8563f860d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php new file mode 100644 index 000000000..8f7f4f93f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php @@ -0,0 +1,78 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::expandSniffDirectory() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandSniffDirectory + */ +final class ExpandSniffDirectoryTest extends TestCase +{ + + + /** + * Test finding sniff files based on a given directory. + * + * This test verifies that: + * - Hidden (sub)directories are ignored, but the given directory is allowed to be within a hidden directory. + * - Hidden files are ignored. + * - Files without a "php" extension are ignored. + * - Files without a "Sniff" suffix in the file name are ignored. + * + * Note: the "[Another]AbstractSniff" files will be found and included in the return value + * from `Ruleset::expandSniffDirectory()`. + * Those are filtered out later in the `Ruleset::registerSniffs()` method. + * + * @return void + */ + public function testExpandSniffDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandSniffDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expectedPathToRuleset = __DIR__.'/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/ruleset.xml'; + $expectedPathToRuleset = realpath($expectedPathToRuleset); + $this->assertNotFalse($expectedPathToRuleset, 'Ruleset file could not be found'); + $this->assertContains($expectedPathToRuleset, $ruleset->paths, 'Ruleset file not included in the "seen ruleset paths"'); + + /* + * Take note: the expectation includes some "undesirables" related to the convoluted directory structure + * in the "standard" used as a test fixture. + * + * That is okay as (for now) non-standard directory layouts are supported. + * + * This test is not about the standard directory layout. + */ + + $expectedSniffCodes = [ + '.Sniffs.IncorrectLevelShouldStillBeFound' => 'MyStandard\\Sniffs\\IncorrectLevelShouldStillBeFoundSniff', + 'MyStandard.CategoryA.FindMe' => 'MyStandard\\Sniffs\\CategoryA\\FindMeSniff', + 'MyStandard.CategoryB.FindMe' => 'MyStandard\\Sniffs\\CategoryB\\FindMeSniff', + 'Sniffs.SubDir.IncorrectLevelShouldStillBeFound' => 'MyStandard\\Sniffs\\CategoryA\\SubDir\\IncorrectLevelShouldStillBeFoundSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expectedSniffCodes, $actual, 'Registered sniffs do not match expectation'); + + }//end testExpandSniffDirectory() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml new file mode 100644 index 000000000..f2646da02 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml new file mode 100644 index 000000000..cbca4fd51 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml new file mode 100644 index 000000000..159b7efa8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php new file mode 100644 index 000000000..3e52cef68 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php @@ -0,0 +1,212 @@ + + * @copyright 2023 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::explain() function. + * + * @covers \PHP_CodeSniffer\Ruleset::explain + */ +final class ExplainTest extends TestCase +{ + + + /** + * Test the output of the "explain" command. + * + * @return void + */ + public function testExplain() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1', '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplain() + + + /** + * Test the output of the "explain" command is not influenced by a user set report width. + * + * @return void + */ + public function testExplainAlwaysDisplaysCompleteSniffName() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1', '-e', '--report-width=30']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainAlwaysDisplaysCompleteSniffName() + + + /** + * Test the output of the "explain" command when a ruleset only contains a single sniff. + * + * This is mostly about making sure that the summary line uses the correct grammar. + * + * @return void + */ + public function testExplainSingleSniff() + { + // Set up the ruleset. + $standard = __DIR__.'/ExplainSingleSniffTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The ExplainSingleSniffTest standard contains 1 sniff'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainSingleSniff() + + + /** + * Test that "explain" works correctly with custom rulesets. + * + * Verifies that: + * - The "standard" name is taken from the custom ruleset. + * - Any and all sniff additions and exclusions in the ruleset are taken into account correctly. + * - That the displayed list will have both the standards as well as the sniff names + * ordered alphabetically. + * + * @return void + */ + public function testExplainCustomRuleset() + { + // Set up the ruleset. + $standard = __DIR__.'/ExplainCustomRulesetTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The ExplainCustomRulesetTest standard contains 10 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (2 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'PSR12 (2 sniffs)'.PHP_EOL; + $expected .= '----------------'.PHP_EOL; + $expected .= ' PSR12.ControlStructures.BooleanOperatorPlacement'.PHP_EOL; + $expected .= ' PSR12.ControlStructures.ControlStructureSpacing'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (2 sniffs)'.PHP_EOL; + $expected .= '----------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainCustomRuleset() + + + /** + * Test the output of the "explain" command for a standard containing both deprecated + * and non-deprecated sniffs. + * + * Tests that: + * - Deprecated sniffs are marked with an asterix in the list. + * - A footnote is displayed explaining the asterix. + * - And that the "standard uses # deprecated sniffs" listing is **not** displayed. + * + * @return void + */ + public function testExplainWithDeprecatedSniffs() + { + // Set up the ruleset. + $standard = __DIR__."/ShowSniffDeprecationsTest.xml"; + $config = new ConfigDouble(["--standard=$standard", '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The ShowSniffDeprecationsTest standard contains 11 sniffs'.PHP_EOL.PHP_EOL; + + $expected .= 'TestStandard (11 sniffs)'.PHP_EOL; + $expected .= '------------------------'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithLongReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithoutReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacementContainingLinuxNewlines *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacementContainingNewlines *'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedAsDeclared'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedViaMagicMethod'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedViaStdClass'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.NotAllowedViaAttribute'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.PropertyTypeHandling'.PHP_EOL; + $expected .= ' TestStandard.ValidSniffs.RegisterEmptyArray'.PHP_EOL.PHP_EOL; + + $expected .= '* Sniffs marked with an asterix are deprecated.'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainWithDeprecatedSniffs() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/.hidden/HiddenDirShouldBeIgnoredSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/.hidden/HiddenDirShouldBeIgnoredSniff.php new file mode 100644 index 000000000..3ee64dbba --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/.hidden/HiddenDirShouldBeIgnoredSniff.php @@ -0,0 +1,15 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php new file mode 100644 index 000000000..51061e3b5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php new file mode 100644 index 000000000..1584f7050 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php new file mode 100644 index 000000000..9346df9eb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php new file mode 100644 index 000000000..e7a04f495 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php @@ -0,0 +1,25 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs new file mode 100644 index 000000000..e69de29bb diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml new file mode 100644 index 000000000..b85e7486e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php new file mode 100644 index 000000000..2b1fadaf5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php @@ -0,0 +1,8 @@ +string,10=>10,float=>1.5,null=>null,true=>true,false=>false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsEmptyArray[] + +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithOnlyValues[] string, 10, 1.5, null, true, false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithKeysAndValues[] string=>string,10=>10,float=>1.5,null=>null,true=>true,false=>false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolEmptyArray[] + +echo 'hello!'; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php new file mode 100644 index 000000000..659d89ee2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php @@ -0,0 +1,41 @@ +magic[$name] = $value; + } + + public function __get($name) + { + if (isset($this->magic[$name])) { + return $this->magic[$name]; + } + + return null; + } + + public function register() + { + return [T_WHITESPACE]; + } + + public function process(File $phpcsFile, $stackPtr) + { + // Do something. + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php new file mode 100644 index 000000000..0f58b2e00 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php @@ -0,0 +1,26 @@ + + */ + public $expectsArrayWithOnlyValues; + + /** + * Used to verify that array properties with keys get parsed to a proper array. + * + * @var array + */ + public $expectsArrayWithKeysAndValues; + + /** + * Used to verify that array properties can get extended. + * + * @var array + */ + public $expectsArrayWithExtendedValues; + + /** + * Used to verify that array properties can get extended. + * + * @var array + */ + public $expectsArrayWithExtendedKeysAndValues; + + /** + * Used to verify that array properties allow for setting a property to an empty array. + * + * @var array + */ + public $expectsEmptyArray; + + /** + * Used to verify that array properties passed as a string get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithOnlyValues; + + /** + * Used to verify that array properties passed as a string with keys get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithKeysAndValues; + + /** + * Used to verify that array properties passed as a string can get extended. + * + * @var array + */ + public $expectsOldSchoolArrayWithExtendedValues; + + /** + * Used to verify that array properties passed as a string can get extended. + * + * @var array + */ + public $expectsOldSchoolArrayWithExtendedKeysAndValues; + + /** + * Used to verify that array properties passed as a string allow for setting a property to an empty array. + * + * @var array + */ + public $expectsOldSchoolEmptyArray; + + public function register() + { + return [T_ECHO]; + } + + public function process(File $phpcsFile, $stackPtr) + { + // Do something. + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/ValidSniffs/RegisterEmptyArraySniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/ValidSniffs/RegisterEmptyArraySniff.php new file mode 100644 index 000000000..2d58e9527 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/ValidSniffs/RegisterEmptyArraySniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php new file mode 100644 index 000000000..ae6b8bea5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIgnorePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIgnorePatterns + */ +final class GetIgnorePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIgnorePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving ignore patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIgnorePatterns + * + * @return void + */ + public function testGetIgnorePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIgnorePatterns($listener)); + + }//end testGetIgnorePatterns() + + + /** + * Data provider. + * + * @see self::testGetIgnorePatterns() + * + * @return array>|null>> + */ + public static function dataGetIgnorePatterns() + { + return [ + 'All ignore patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + './tests/' => 'absolute', + './vendor/*' => 'absolute', + '*/node-modules/*' => 'relative', + ], + ], + 'Ignore patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Ignore patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Ignore patterns for sniff without ignore patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIgnorePatterns() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml new file mode 100644 index 000000000..7fcfdc237 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml @@ -0,0 +1,19 @@ + + + + ./tests/ + ./vendor/* + */node-modules/* + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php new file mode 100644 index 000000000..a38401b61 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php @@ -0,0 +1,108 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIncludePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIncludePatterns + */ +final class GetIncludePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIncludePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving include patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIncludePatterns + * + * @return void + */ + public function testGetIncludePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIncludePatterns($listener)); + + }//end testGetIncludePatterns() + + + /** + * Data provider. + * + * @see self::testGetIncludePatterns() + * + * @return array>|null>> + */ + public static function dataGetIncludePatterns() + { + return [ + 'All include patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + ], + ], + 'Include patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Include patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Include patterns for sniff without include patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIncludePatterns() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml new file mode 100644 index 000000000..c24f93f54 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml @@ -0,0 +1,15 @@ + + + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml new file mode 100644 index 000000000..52a406a69 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php new file mode 100644 index 000000000..6f79c10da --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php @@ -0,0 +1,553 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use PHP_CodeSniffer\Util\Tokens; +use ReflectionObject; +use ReflectionProperty; + +/** + * Test the Ruleset::populateTokenListeners() method. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Test an exception is thrown when the register() method of a sniff doesn't return an array. + * + * @return void + */ + public function testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + { + $standard = __DIR__.'/PopulateTokenListenersRegisterNoArrayTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $sniffClass = 'Fixtures\\TestStandard\\Sniffs\\InvalidSniffs\\RegisterNoArraySniff'; + $message = "ERROR: The sniff {$sniffClass}::register() method must return an array.".PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + // Verify that the sniff has not been registered/has been unregistered. + // These assertions will only take effect for PHPUnit 10+. + $this->assertArrayNotHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass is listed in registered sniffs"); + $this->assertArrayNotHasKey('TestStandard.InvalidSniffs.RegisterNoArray', self::$ruleset->sniffCodes, 'Sniff code is registered'); + + }//end testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + + + /** + * Test that a sniff not registering any tokens is not listed as a listener. + * + * @return void + */ + public function testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + { + $target = 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + $this->assertArrayNotHasKey( + $target, + $listeners, + sprintf('Found the %s sniff registered for token %s', $target, Tokens::tokenName($token)) + ); + } + + }//end testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + + + /** + * Tests that sniffs registering tokens, will end up listening to these tokens. + * + * @param string $sniffClass The FQN for the sniff class to check. + * @param int $expectedCount Expected number of tokens to which the sniff should be listening. + * + * @dataProvider dataSniffListensToTokenss + * + * @return void + */ + public function testRegistersSniffsToListenToTokens($sniffClass, $expectedCount) + { + $counter = 0; + + foreach (self::$ruleset->tokenListeners as $listeners) { + if (isset($listeners[$sniffClass]) === true) { + ++$counter; + } + } + + $this->assertSame($expectedCount, $counter); + + }//end testRegistersSniffsToListenToTokens() + + + /** + * Data provider. + * + * @see testSniffListensToTokens() + * + * @return array> + */ + public static function dataSniffListensToTokenss() + { + return [ + 'Generic.Files.EndFileNewline' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\EndFileNewlineSniff', + 'expectedCount' => 2, + ], + 'Generic.NamingConventions.UpperCaseConstantName' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'expectedCount' => 2, + ], + 'PSR1.Files.SideEffects' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'expectedCount' => 1, + ], + 'PSR12.ControlStructures.BooleanOperatorPlacement' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'expectedCount' => 5, + ], + 'Squiz.ControlStructures.ForEachLoopDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'expectedCount' => 1, + ], + 'TestStandard.Deprecated.WithReplacement' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\Deprecated\\WithReplacementSniff', + 'expectedCount' => 1, + ], + 'TestStandard.ValidSniffs.RegisterEmptyArray' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff', + 'expectedCount' => 0, + ], + ]; + + }//end dataSniffListensToTokenss() + + + /** + * Test that deprecated sniffs get recognized and added to the $deprecatedSniffs list. + * + * @return void + */ + public function testRegistersWhenADeprecatedSniffIsLoaded() + { + $property = new ReflectionProperty(self::$ruleset, 'deprecatedSniffs'); + $property->setAccessible(true); + $actualValue = $property->getValue(self::$ruleset); + $property->setAccessible(false); + + // Only verify there is one deprecated sniff registered. + // There are other tests which test the deprecated sniff handling in more detail. + $this->assertTrue(is_array($actualValue)); + $this->assertCount(1, $actualValue); + + }//end testRegistersWhenADeprecatedSniffIsLoaded() + + + /** + * Verify that the setting of properties on a sniff was not triggered when there are no properties being set. + * + * @return void + */ + public function testDoesntTriggerPropertySettingForNoProperties() + { + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $reflection = new ReflectionObject($sniffObject); + + // Just making sure there are no properties on the sniff object (which doesn't have declared properties). + $this->assertSame([], $reflection->getProperties(), "Unexpected properties found on sniff class $sniffClass"); + + }//end testDoesntTriggerPropertySettingForNoProperties() + + + /** + * Verify that the setting of properties on a sniff was triggered. + * + * @param string $sniffClass The FQN for the sniff class on which the property should be set. + * @param string $propertyName The property name. + * @param string $expected The expected property value. + * + * @dataProvider dataTriggersPropertySettingWhenPropertiesProvided + * + * @return void + */ + public function testTriggersPropertySettingWhenPropertiesProvided($sniffClass, $propertyName, $expected) + { + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify the property has been set. + $this->assertSame($expected, $sniffObject->$propertyName, "Property on sniff class $sniffClass set to unexpected value"); + + }//end testTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Data provider. + * + * @see testTriggersPropertySettingWhenPropertiesProvided() + * + * @return array> + */ + public static function dataTriggersPropertySettingWhenPropertiesProvided() + { + return [ + 'Sniff with single property being set' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'propertyName' => 'allowOnly', + 'expected' => 'first', + ], + 'Sniff with multiple properties being set - first property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesAfterOpen', + 'expected' => '3', + ], + 'Sniff with multiple properties being set - second property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesBeforeClose', + 'expected' => '8', + ], + ]; + + }//end dataTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Verifies that the "class" and "source" indexes get set. + * + * @return void + */ + public function testSetsClassAndSourceIndexes() + { + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + $this->assertArrayHasKey( + 'class', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $className, + $details['class'], + sprintf('Unexpected value for "class" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertArrayHasKey( + 'source', + $details, + sprintf('"source" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertTrue( + is_string($details['source']), + sprintf('Value for "source" key is not a string for token %s', Tokens::tokenName($token)) + ); + + $expected = '.'.substr($className, (strrpos($className, '\\') + 1), -5); + + $this->assertStringEndsWith( + $expected, + $details['source'], + sprintf('Unexpected value for "source" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + }//end foreach + }//end foreach + + }//end testSetsClassAndSourceIndexes() + + + /** + * Verifies that sniffs by default are listening for PHP files only. + * + * @return void + */ + public function testSetsSupportedTokenizersToPHPByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\EndFileNewlineSniff'; + $expected = ['PHP' => 'PHP']; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'tokenizers', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + $details['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsSupportedTokenizersToPHPByDefault() + + + /** + * Test that if a sniff has the $supportedTokenizers property set, the tokenizers listed there + * will be registered in the listeners array. + * + * @param int $token The token constant for which the sniff should be registered. + * + * @dataProvider dataSetsSupportedTokenizersWhenProvidedBySniff + * + * @return void + */ + public function testSetsSupportedTokenizersWhenProvidedBySniff($token) + { + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\EndFileNewlineSniff'; + $expected = [ + 'PHP' => 'PHP', + 'JS' => 'JS', + 'CSS' => 'CSS', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + 'tokenizers', + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"tokenizers" key missing for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass]['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Data provider. + * + * @see testSetsSupportedTokenizersWhenProvidedBySniff() + * + * @return array> + */ + public static function dataSetsSupportedTokenizersWhenProvidedBySniff() + { + return [ + 'T_OPEN_TAG' => [T_OPEN_TAG], + 'T_OPEN_TAG_WITH_ECHO' => [T_OPEN_TAG_WITH_ECHO], + ]; + + }//end dataSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Verifies that by default no explicit include patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIncludePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'include', + $details, + sprintf('"include" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['include'], + sprintf('Unexpected value for "include" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIncludePatternsToEmptyArrayByDefault() + + + /** + * Verifies that by default no explicit ignore patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIgnorePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'ignore', + $details, + sprintf('"ignore" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['ignore'], + sprintf('Unexpected value for "ignore" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIgnorePatternsToEmptyArrayByDefault() + + + /** + * Tests that if there are <[include|exclude]-pattern> directives set on a sniff, these are set for the relevant listeners. + * + * Includes verification that the transformation of "regex"-like patterns is handled correctly. + * + * @param int|string $token A token constant on which the sniff should be registered. + * @param string $sniffClass The FQN for the sniff class on which the patterns should be registered. + * @param string $patternType The type of patterns expected to be registered for the sniff. + * + * @dataProvider dataSetsIncludeAndIgnorePatterns + * + * @return void + */ + public function testSetsIncludeAndIgnorePatterns($token, $sniffClass, $patternType) + { + $expected = [ + '/no-transformation/', + '/simple.*transformation/.*', + '/escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css', + '/pat?tern(is|regex)\\.php$', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $patternType, + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"%s" key missing for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass][$patternType], + sprintf('Unexpected value for "%s" key for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsIncludeAndIgnorePatterns() + + + /** + * Data provider. + * + * @see testSetsIncludeAndIgnorePatterns() + * + * @return array> + */ + public static function dataSetsIncludeAndIgnorePatterns() + { + return [ + 'Sniff with s in the ruleset - first token' => [ + 'token' => T_STRING, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset - second token' => [ + 'token' => T_CONST, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset' => [ + 'token' => T_OPEN_TAG, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'patternType' => 'ignore', + ], + ]; + + }//end dataSetsIncludeAndIgnorePatterns() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml new file mode 100644 index 000000000..f61ab500d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php new file mode 100644 index 000000000..d43958c77 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php @@ -0,0 +1,43 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of invalid type elements. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + */ +final class ProcessRuleInvalidTypeTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an error when an invalid type is given. + * + * @return void + */ + public function testInvalidTypeHandling() + { + $standard = __DIR__.'/ProcessRuleInvalidTypeTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'ERROR: Message type "notice" for "Generic.Files.ByteOrderMark" is invalid; must be "error" or "warning".'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testInvalidTypeHandling() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml new file mode 100644 index 000000000..63c2aaf3c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml @@ -0,0 +1,9 @@ + + + + + + notice + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php new file mode 100644 index 000000000..c6c9e2160 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php @@ -0,0 +1,666 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at rule level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRuleShouldProcessElementTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRuleShouldProcessElementTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessSeverityCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'Internal.NoCodeFound'; + $this->assertRulesetPropertySame(0, $sniffCode, $key); + + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame(2, $sniffCode, $key); + + // Verify that the CBF-only severity directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessSeverityCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessSeverityCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only severity directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame(4, $sniffCode, $key); + + }//end testShouldProcessSeverityCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessTypeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CBF-only type directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessTypeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessTypeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only type directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('error', $sniffCode, $key); + + }//end testShouldProcessTypeCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessMessageCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('A different warning but only for phpcs', $sniffCode, $key); + + // Verify that the CBF-only message directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessMessageCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessMessageCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'Internal.NoCodeFound'; + $this->assertRulesetPropertySame("We don't to be notified if files don't contain code", $sniffCode, $key); + + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only message directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('A different warning but only for phpcbf', $sniffCode, $key); + + }//end testShouldProcessMessageCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessIncludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive IS applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only include-pattern directive is NOT applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessIncludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessIncludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive is NOT applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only include-pattern directive is IS applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessIncludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive IS applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only exclude-pattern directive is NOT applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive is NOT applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only exclude-pattern directive is IS applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertiesCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive IS applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertiesCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertiesCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive is NOT applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertiesCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertyCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive IS applied. + $propertyName = 'indent'; + $expected = '2'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $propertyName = 'tabIndent'; + $expectedDefault = false; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertyCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertyCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive is NOT applied. + $propertyName = 'indent'; + $expectedDefault = 4; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $propertyName = 'tabIndent'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertyCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessElementCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcs-only element directive. + 'T_CLASS', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcs-only element directive via `extend`. + 'T_INTERFACE', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessElementCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcbf-only element directive. + 'T_ENUM', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcbf-only element directive via `extend`. + 'T_TRAIT', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCbfonly() + + + /** + * Verify that directives are set correctly. + * + * @param array $expected Expected sniff property value. + * + * @return void + */ + private function verifyShouldProcessElement($expected) + { + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + // Verify the target property exists. + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $propertyName = 'ignoreIndentationTokens'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + + // Verify the value. + $actualValue = $sniffObject->$propertyName; + $this->assertSame($expected, $actualValue, 'Selective element directives not applied correctly'); + + }//end verifyShouldProcessElement() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property has a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertHasRulesetDirective($sniffCode, $key) + { + $this->assertArrayHasKey($sniffCode, self::$ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array(self::$ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, self::$ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + + }//end assertHasRulesetDirective() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property does NOT have a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertNotHasRulesetDirective($sniffCode, $key) + { + if (isset(self::$ruleset->ruleset[$sniffCode]) === true + && is_array(self::$ruleset->ruleset[$sniffCode]) === true + && isset(self::$ruleset->ruleset[$sniffCode][$key]) === true + ) { + $this->fail("Directive $key is registered for sniff $sniffCode"); + } + + }//end assertNotHasRulesetDirective() + + + /** + * Custom assertion to verify that the value of a certain directive for a certain sniff code on the ruleset is correct. + * + * @param mixed $expected Expected value. + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertRulesetPropertySame($expected, $sniffCode, $key) + { + $this->assertHasRulesetDirective($sniffCode, $key); + + $actual = self::$ruleset->ruleset[$sniffCode][$key]; + $this->assertSame($expected, $actual, "Value for $key on sniff $sniffCode does not meet expectations"); + + }//end assertRulesetPropertySame() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml new file mode 100644 index 000000000..3fbfd6d55 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml @@ -0,0 +1,105 @@ + + + + + + 0 + We don't to be notified if files don't contain code + + + + 3 + warning + A different warning message + + + + ./vendor/ + + + + ./tests/ + + + + + + + 2 + warning + A different warning but only for phpcs + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + 4 + error + A different warning but only for phpcbf + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml new file mode 100644 index 000000000..3b8b4c9b4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml new file mode 100644 index 000000000..196baa6cd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml @@ -0,0 +1,8 @@ + + + + ./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php new file mode 100644 index 000000000..1f6e289e6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php @@ -0,0 +1,164 @@ + instructions. + * + * @author Juliette Reinders Folmer + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of instructions. + * + * Note: these tests need to run in separate processes as otherwise we cannot + * reliably determine whether or not the correct files were loaded as the + * underlying code uses `include_once`. + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetAutoloadTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessAutoloadCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + + }//end testShouldProcessAutoloadCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessAutoloadCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was not loaded' + ); + + }//end testShouldProcessAutoloadCbfonly() + + + /** + * Test an exception is thrown when the directive points to a file which doesn't exist. + * + * @return void + */ + public function testFileNotFoundException() + { + $exceptionMsg = 'ERROR: The specified autoload file "./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php" does not exist'; + $this->expectRuntimeExceptionMessage($exceptionMsg); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadFileNotFoundTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testFileNotFoundException() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml new file mode 100644 index 000000000..450de6507 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml @@ -0,0 +1,37 @@ + + + + . + + + + ./Fixtures/ProcessRulesetAutoloadLoadAlways.1.php + Fixtures/ProcessRulesetAutoloadLoadAlways.2.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php + tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml new file mode 100644 index 000000000..e69de29bb diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml new file mode 100644 index 000000000..64294b9b7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml new file mode 100644 index 000000000..e9c5bd7e4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml @@ -0,0 +1,2 @@ + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php new file mode 100644 index 000000000..2798c2fc6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php @@ -0,0 +1,96 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of broken ruleset files. + * + * Note: these tests need to run in separate processes as otherwise they run into + * some weirdness with the libxml_get_errors()/libxml_clear_errors() functions + * (duplicate error messages). + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @group Windows + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetBrokenRulesetTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an informative error message when an empty XML ruleset file is encountered. + * + * @return void + */ + public function testBrokenRulesetEmptyFile() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetEmptyFileTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetEmptyFileTest\.xml is not valid\R'; + $regex .= '(- On line 1, column 1: Document is empty\R)?$`'; + + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetEmptyFile() + + + /** + * Test displaying an informative error message for a broken XML ruleset with a single XML error. + * + * @return void + */ + public function testBrokenRulesetSingleError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetSingleErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetSingleErrorTest\.xml is not valid\R'; + $regex .= '- On line 3, column 1: (Premature end of data in tag ruleset line 2|EndTag: \'expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetSingleError() + + + /** + * Test displaying an informative error message for a broken XML ruleset with multiple XML errors. + * + * @return void + */ + public function testBrokenRulesetMultiError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetMultiErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetMultiErrorTest\.xml is not valid\R'; + $regex .= '- On line 8, column 12: Opening and ending tag mismatch: property line 7 and rule\R'; + $regex .= '- On line 10, column 11: Opening and ending tag mismatch: properties line [57] and ruleset\R'; + $regex .= '(- On line 11, column 1: (Premature end of data in tag rule(set)? line [24]|EndTag: \'expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetMultiError() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml new file mode 100644 index 000000000..a83347ce8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml new file mode 100644 index 000000000..daa07f2e2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml new file mode 100644 index 000000000..56bf68981 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php new file mode 100644 index 000000000..1f0780c44 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php @@ -0,0 +1,388 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at ruleset level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRulesetShouldProcessElementTest extends TestCase +{ + + /** + * Cache to store the original ini values for ini settings being changed in these tests. + * + * @var array + */ + private static $originalIniValues = [ + 'bcmath.scale' => null, + 'docref_root' => null, + 'user_agent' => null, + ]; + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Tests\ConfigDouble + */ + private static $config; + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Store the original ini values to allow for restoring them after the tests. + * + * @beforeClass + * + * @return void + */ + public static function saveOriginalIniValues() + { + foreach (self::$originalIniValues as $name => $null) { + $value = ini_get($name); + if ($value !== false) { + self::$originalIniValues[$name] = $value; + } + } + + }//end saveOriginalIniValues() + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetShouldProcessElementTest.xml'; + self::$config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset(self::$config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Destroy the Config object and restore the ini values after the tests. + * + * @afterClass + * + * @return void + */ + public static function restoreOriginalValues() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when this object is destroyed, but we can't definitively rely on that). + if (isset(self::$config) === true) { + self::$config->__destruct(); + } + + foreach (self::$originalIniValues as $name => $value) { + if ($value === null) { + continue; + } + + ini_set($name, $value); + } + + }//end restoreOriginalValues() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessConfigCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame('true', Config::getConfigData('csOnly'), 'CS-only config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('cbfOnly'), 'CBF-only config directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessConfigCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessConfigCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('csOnly'), 'CS-only config directive was applied, while it shouldn\'t have been.'); + $this->assertSame('true', Config::getConfigData('cbfOnly'), 'CBF-only config directive was not applied.'); + + }//end testShouldProcessConfigCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessArgCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['full' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertTrue(self::$config->colors, 'CS-only arg directive was not applied.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessArgCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessArgCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['summary' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertFalse(self::$config->colors, 'CS-only arg directive was applied, while it shouldn\'t have been.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was not applied.'); + + }//end testShouldProcessArgCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessIniCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('path/to/docs/', ini_get('docref_root'), 'CS-only ini directive was not applied.'); + $this->assertSame('', ini_get('user_agent'), 'CBF-only ini directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessIniCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessIniCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('', ini_get('docref_root'), 'CS-only ini directive was applied, while it shouldn\'t have been..'); + $this->assertSame('Never mind', ini_get('user_agent'), 'CBF-only ini directive was not applied.'); + + }//end testShouldProcessIniCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './vendor/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './node-modules/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCbfonly() + + + /** + * Verify that in CS mode, phpcs-only in directives are respected and phpcbf-only in + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleExcludeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.Indent' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only in directives are respected and phpcs-only in + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleExcludeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.EqualSignLine' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCbfonly() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml new file mode 100644 index 000000000..62ea0e62f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml @@ -0,0 +1,54 @@ + + + + . + + + + + + + + ./tests/ + + + + + + + + + ./vendor/ + + + + + + + + + + + + + ./node-modules/ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php new file mode 100644 index 000000000..fa704bef5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php @@ -0,0 +1,264 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test various aspects of the Ruleset::processRuleset() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetTest extends TestCase +{ + + + /** + * Verify that a registered standard which doesn't have a "Sniffs" directory, but does have a file + * called "Sniffs" doesn't result in any errors being thrown. + * + * @return void + */ + public function testSniffsFileNotDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetInvalidNoSniffsDirTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\BacktickOperatorSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testSniffsFileNotDirectory() + + + /** + * Verify that all sniffs in a registered standard included in a ruleset automatically get added. + * + * @return void + */ + public function testAutoExpandSniffsDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoExpandSniffsDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $std = 'TestStandard'; + $sniffDir = 'Fixtures\TestStandard\Sniffs'; + $expected = [ + "$std.Deprecated.WithLongReplacement" => "$sniffDir\Deprecated\WithLongReplacementSniff", + "$std.Deprecated.WithReplacement" => "$sniffDir\Deprecated\WithReplacementSniff", + "$std.Deprecated.WithReplacementContainingLinuxNewlines" => "$sniffDir\Deprecated\WithReplacementContainingLinuxNewlinesSniff", + "$std.Deprecated.WithReplacementContainingNewlines" => "$sniffDir\Deprecated\WithReplacementContainingNewlinesSniff", + "$std.Deprecated.WithoutReplacement" => "$sniffDir\Deprecated\WithoutReplacementSniff", + "$std.DeprecatedInvalid.EmptyDeprecationVersion" => "$sniffDir\DeprecatedInvalid\EmptyDeprecationVersionSniff", + "$std.DeprecatedInvalid.EmptyRemovalVersion" => "$sniffDir\DeprecatedInvalid\EmptyRemovalVersionSniff", + "$std.DeprecatedInvalid.InvalidDeprecationMessage" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationMessageSniff", + "$std.DeprecatedInvalid.InvalidDeprecationVersion" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationVersionSniff", + "$std.DeprecatedInvalid.InvalidRemovalVersion" => "$sniffDir\DeprecatedInvalid\InvalidRemovalVersionSniff", + "$std.SetProperty.AllowedAsDeclared" => "$sniffDir\SetProperty\AllowedAsDeclaredSniff", + "$std.SetProperty.AllowedViaMagicMethod" => "$sniffDir\SetProperty\AllowedViaMagicMethodSniff", + "$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff", + "$std.SetProperty.NotAllowedViaAttribute" => "$sniffDir\SetProperty\NotAllowedViaAttributeSniff", + "$std.SetProperty.PropertyTypeHandling" => "$sniffDir\SetProperty\PropertyTypeHandlingSniff", + "$std.ValidSniffs.RegisterEmptyArray" => "$sniffDir\ValidSniffs\RegisterEmptyArraySniff", + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testAutoExpandSniffsDirectory() + + + /** + * Verify handling of exclusions of groups of sniffs after inclusion via an even larger "group". + * + * @return void + */ + public function testExcludeSniffGroup() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetExcludeSniffGroupTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = [ + 'PSR1.Classes.ClassDeclaration' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', + 'PSR1.Methods.CamelCapsMethodName' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testExcludeSniffGroup() + + + /* + * No test for without "name" as there is nothing we can assert to verify it's being ignored. + */ + + + /** + * Test that an `` directive without a "value" attribute will be set to the ini equivalent of `true`. + * + * @return void + */ + public function testIniWithoutValue() + { + $originalValue = ini_get('user_agent'); + + // Set up the ruleset. + $this->getMiscRuleset(); + + $actualValue = ini_get('user_agent'); + // Reset the ini to its original value before the assertion to ensure it's never left in an incorrect state. + if ($originalValue !== false) { + ini_set('user_agent', $originalValue); + } + + $this->assertSame('1', $actualValue); + + }//end testIniWithoutValue() + + + /** + * Verify that inclusion of a single error code: + * - Includes the sniff, but sets "severity" for the sniff to 0; + * - Sets "severity" for the specific error code included to 5.; + * + * @return void + */ + public function testIncludeSingleErrorCode() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'Generic.PHP.RequireStrictTypes'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'Generic.PHP.RequireStrictTypes.MissingDeclaration'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testIncludeSingleErrorCode() + + + /** + * Verify that if all error codes, save one, from a sniff were previously excluded, an include for an additional + * error code from that same sniff will be respected. + * + * @return void + */ + public function testErrorCodeIncludeAfterExclude() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'PEAR.Files.IncludingFile'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.BracketsNotRequired'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.UseRequire'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testErrorCodeIncludeAfterExclude() + + + /** + * Verify that a element without a "ref" is completely ignored. + * + * @return void + */ + public function testRuleWithoutRefIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleWithoutRefIsIgnored() + + + /** + * Verify that no "ruleset adjustments" are registered via an `` without a "name". + * + * @return void + */ + public function testRuleExcludeWithoutNameIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.PHP.BacktickOperator'; + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode not registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + $sniffCode = 'Generic.PHP.BacktickOperator.Found'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleExcludeWithoutNameIsIgnored() + + + /** + * Test Helper. + * + * @return \PHP_CodeSniffer\Ruleset + */ + private function getMiscRuleset() + { + static $ruleset; + + if (isset($ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetMiscTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + } + + return $ruleset; + + }//end getMiscRuleset() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml new file mode 100644 index 000000000..0bdadc7de --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php new file mode 100644 index 000000000..346914b14 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php @@ -0,0 +1,301 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the handling of property value types for properties set via the ruleset and inline. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty + */ +final class PropertyTypeHandlingTest extends TestCase +{ + + /** + * Sniff code for the sniff used in these tests. + * + * @var string + */ + const SNIFF_CODE = 'TestStandard.SetProperty.PropertyTypeHandling'; + + /** + * Class name of the sniff used in these tests. + * + * @var string + */ + const SNIFF_CLASS = 'Fixtures\\TestStandard\\Sniffs\\SetProperty\\PropertyTypeHandlingSniff'; + + + /** + * Test the value type handling for properties set via a ruleset. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * @dataProvider dataArrayPropertyExtending + * + * @return void + */ + public function testTypeHandlingWhenSetViaRuleset($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectForRuleset(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetViaRuleset() + + + /** + * Test the value type handling for properties set inline in a test case file. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * + * @return void + */ + public function testTypeHandlingWhenSetInline($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectAfterProcessingFile(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetInline() + + + /** + * Data provider. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * @see self::testTypeHandlingWhenSetInline() + * + * @return array> + */ + public static function dataTypeHandling() + { + $expectedArrayOnlyValues = [ + 'string', + '10', + '1.5', + 'null', + 'true', + 'false', + ]; + $expectedArrayKeysAndValues = [ + 'string' => 'string', + 10 => '10', + 'float' => '1.5', + 'null' => 'null', + 'true' => 'true', + 'false' => 'false', + ]; + + return [ + 'String value (default)' => [ + 'propertyName' => 'expectsString', + 'expected' => 'arbitraryvalue', + ], + 'String value with whitespace gets trimmed' => [ + 'propertyName' => 'expectsTrimmedString', + 'expected' => 'some value', + ], + 'String with whitespace only value becomes null' => [ + 'propertyName' => 'emptyStringBecomesNull', + 'expected' => null, + ], + 'Integer value gets set as string' => [ + 'propertyName' => 'expectsIntButAcceptsString', + 'expected' => '12345', + ], + 'Float value gets set as string' => [ + 'propertyName' => 'expectsFloatButAcceptsString', + 'expected' => '12.345', + ], + 'Null value gets set as string' => [ + 'propertyName' => 'expectsNull', + 'expected' => 'null', + ], + 'Null (uppercase) value gets set as string' => [ + 'propertyName' => 'expectsNullCase', + 'expected' => 'NULL', + ], + 'True value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanTrue', + 'expected' => true, + ], + 'True (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanTrueCase', + 'expected' => 'True', + ], + 'True (with spaces) value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanTrueTrimmed', + 'expected' => true, + ], + 'False value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanFalse', + 'expected' => false, + ], + 'False (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanFalseCase', + 'expected' => 'fALSe', + ], + 'False (with spaces) value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanFalseTrimmed', + 'expected' => false, + ], + 'Array with only values (new style)' => [ + 'propertyName' => 'expectsArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (new style)' => [ + 'propertyName' => 'expectsArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + 'Empty array (new style)' => [ + 'propertyName' => 'expectsEmptyArray', + 'expected' => [], + ], + 'Array with only values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + 'Empty array (old style)' => [ + 'propertyName' => 'expectsOldSchoolEmptyArray', + 'expected' => [], + ], + ]; + + }//end dataTypeHandling() + + + /** + * Data provider. + * + * Array property extending is a feature which is only supported from a ruleset, not for inline property setting. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return array> + */ + public static function dataArrayPropertyExtending() + { + $expectedArrayOnlyValuesExtended = [ + 'string', + '15', + 'another string', + ]; + $expectedArrayKeysAndValuesExtended = [ + 10 => '10', + 'string' => 'string', + 15 => '15', + 'another string' => 'another string', + ]; + + return [ + 'Array with only values extended (new style)' => [ + 'propertyName' => 'expectsArrayWithExtendedValues', + 'expected' => $expectedArrayOnlyValuesExtended, + ], + 'Array with keys and values extended (new style)' => [ + 'propertyName' => 'expectsArrayWithExtendedKeysAndValues', + 'expected' => $expectedArrayKeysAndValuesExtended, + ], + 'Array with only values extended (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithExtendedValues', + 'expected' => $expectedArrayOnlyValuesExtended, + ], + 'Array with keys and values extended (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithExtendedKeysAndValues', + 'expected' => $expectedArrayKeysAndValuesExtended, + ], + ]; + + }//end dataArrayPropertyExtending() + + + /** + * Test Helper. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectForRuleset() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + } + + return $sniffObject; + + }//end getSniffObjectForRuleset() + + + /** + * Test Helper + * + * @see self::testTypeHandlingWhenSetInline() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectAfterProcessingFile() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingInlineTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + + // Process the file with inline phpcs:set annotations. + $testFile = realpath(__DIR__.'/Fixtures/PropertyTypeHandlingInline.inc'); + $this->assertNotFalse($testFile); + + $phpcsFile = new LocalFile($testFile, $ruleset, $config); + $phpcsFile->process(); + } + + return $sniffObject; + + }//end getSniffObjectAfterProcessingFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml new file mode 100644 index 000000000..c69b0394e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml new file mode 100644 index 000000000..6b70d32d8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml new file mode 100644 index 000000000..06e202837 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml new file mode 100644 index 000000000..9e0913f9c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php new file mode 100644 index 000000000..1efe5cdba --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php @@ -0,0 +1,80 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Tests that invalid sniffs will be rejected with an informative error message. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsRejectsInvalidSniffTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that an error is thrown if an invalid sniff class is loaded. + * + * @param string $standard The standard to use for the test. + * @param string $methodName The name of the missing method. + * + * @dataProvider dataExceptionIsThrownOnMissingInterfaceMethod + * + * @return void + */ + public function testExceptionIsThrownOnMissingInterfaceMethod($standard, $methodName) + { + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = "`(^|\R)ERROR: Sniff class \S+Sniff is missing required method $methodName\(\)\.\R`"; + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testExceptionIsThrownOnMissingInterfaceMethod() + + + /** + * Data provider. + * + * @see testExceptionIsThrownOnMissingInterfaceMethod() + * + * @return array> + */ + public static function dataExceptionIsThrownOnMissingInterfaceMethod() + { + return [ + 'Missing register() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml', + 'methodName' => 'register', + ], + 'Missing process() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml', + 'methodName' => 'process', + ], + 'Missing both, checking register() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml', + 'methodName' => 'register', + ], + 'Missing both, checking process() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml', + 'methodName' => 'process', + ], + ]; + + }//end dataExceptionIsThrownOnMissingInterfaceMethod() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php new file mode 100644 index 000000000..1ed3ee182 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::registerSniffs() method. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + /** + * Original value of the $sniffs property on the Ruleset. + * + * @var array + */ + private static $originalSniffs = []; + + /** + * List of Standards dir relative sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffFiles = [ + 'Generic/Sniffs/Files/ByteOrderMarkSniff.php', + 'Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', + 'Generic/Sniffs/PHP/DisallowAlternativePHPTagsSniff.php', + 'Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', + 'PSR1/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR1/Sniffs/Files/SideEffectsSniff.php', + 'PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', + 'Squiz/Sniffs/Classes/ValidClassNameSniff.php', + ]; + + /** + * Absolute paths to the sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffAbsolutePaths = []; + + + /** + * Initialize the config and ruleset objects which will be used for some of these tests. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1']); + self::$ruleset = new Ruleset($config); + + // Remember the original value of the Ruleset::$sniff property as the tests adjust it. + self::$originalSniffs = self::$ruleset->sniffs; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + ksort(self::$originalSniffs); + + // Update the sniff file list. + $standardsDir = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR; + $standardsDir .= 'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + + self::$psr1SniffAbsolutePaths = self::relativeToAbsoluteSniffFiles($standardsDir, self::$psr1SniffFiles); + + }//end initializeConfigAndRuleset() + + + /** + * Convert relative paths to absolute paths and ensure the paths use the correct OS-specific directory separator. + * + * @param string $baseDir Directory to which these paths are relative to. Including trailing slash. + * @param array $relativePaths Relative paths. + * + * @return array + */ + public static function relativeToAbsoluteSniffFiles($baseDir, $relativePaths) + { + $fileList = []; + foreach ($relativePaths as $sniffName) { + $sniffFile = str_replace('/', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = $baseDir.$sniffFile; + $fileList[] = $sniffFile; + } + + return $fileList; + + }//end relativeToAbsoluteSniffFiles() + + + /** + * Clear out the Ruleset::$sniffs property. + * + * @before + * + * @return void + */ + protected function clearOutSniffs() + { + // Clear out the Ruleset::$sniffs property. + self::$ruleset->sniffs = []; + + }//end clearOutSniffs() + + + /** + * Test that registering sniffs works as expected (simple base test case). + * + * @return void + */ + public function testRegisteredSniffsShouldBeTheSame() + { + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsShouldBeTheSame() + + + /** + * Test that if only specific sniffs are requested, only those are registered. + * + * {@internal Can't test this via the CLI arguments due to some code in the Ruleset class + * related to sniff tests.} + * + * @return void + */ + public function testRegisteredSniffsWithRestrictions() + { + $restrictions = [ + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'psr1\\sniffs\\files\\sideeffectssniff' => true, + 'psr1\\sniffs\\methods\\camelcapsmethodnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, []); + + $this->assertSame($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsWithRestrictions() + + + /** + * Test that sniffs excluded via the CLI are not registered. + * + * @return void + */ + public function testRegisteredSniffsWithExclusions() + { + // Set up the ruleset. + $args = [ + '--standard=PSR1', + '--exclude=PSR1.Classes.ClassDeclaration,PSR1.Files.SideEffects,PSR1.Methods.CamelCapsMethodName', + ]; + $config = new ConfigDouble($args); + $ruleset = new Ruleset($config); + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testRegisteredSniffsWithExclusions() + + + /** + * Test combining requesting specific sniffs and excluding a subset of those. + * + * @return void + */ + public function testRegisteredSniffsBothRestrictionsAndExclusions() + { + $restrictions = [ + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\php\\disallowshortopentagsniff' => true, + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + ]; + + $exclusions = [ + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, $exclusions); + + $this->assertSame($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsBothRestrictionsAndExclusions() + + + /** + * Verify that abstract sniffs are filtered out and not registered. + * + * @return void + */ + public function testRegisterSniffsFiltersOutAbstractClasses() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/AbstractSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryB/AnotherAbstractSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisterSniffsFiltersOutAbstractClasses() + + + /** + * Test that sniff files not in a "/Sniffs/" directory are filtered out and not registered. + * + * @return void + */ + public function testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/NotInSniffsDirSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/SubDir/NotInSniffsDirSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php index 8b138e0b0..6eb0d1a20 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php @@ -4,16 +4,21 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Ruleset; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; -class RuleInclusionAbsoluteLinuxTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Ruleset class using a Linux-style absolute path to include a sniff. + * + * @covers \PHP_CodeSniffer\Ruleset + */ +final class RuleInclusionAbsoluteLinuxTest extends TestCase { /** @@ -41,17 +46,12 @@ class RuleInclusionAbsoluteLinuxTest extends TestCase /** * Initialize the config and ruleset objects. * + * @before + * * @return void */ - public function setUp() + protected function initializeConfigAndRuleset() { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - $this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; $repoRootDir = dirname(dirname(dirname(__DIR__))); @@ -71,22 +71,24 @@ public function setUp() } // Initialize the config and ruleset objects for the test. - $config = new Config(["--standard={$this->standard}"]); + $config = new ConfigDouble(["--standard={$this->standard}"]); $this->ruleset = new Ruleset($config); - }//end setUp() + }//end initializeConfigAndRuleset() /** * Reset ruleset file. * + * @after + * * @return void */ - public function tearDown() + protected function resetRuleset() { file_put_contents($this->standard, $this->contents); - }//end tearDown() + }//end resetRuleset() /** @@ -98,7 +100,6 @@ public function tearDown() public function testLinuxStylePathRuleInclusion() { // Test that the sniff is correctly registered. - $this->assertObjectHasAttribute('sniffCodes', $this->ruleset); $this->assertCount(1, $this->ruleset->sniffCodes); $this->assertArrayHasKey('Generic.Formatting.SpaceAfterNot', $this->ruleset->sniffCodes); $this->assertSame( diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml index 64d1aae68..2978cef9f 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php index f8e3255b8..fc5d65488 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php @@ -4,16 +4,23 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Ruleset; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; -class RuleInclusionAbsoluteWindowsTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Ruleset class using a Windows-style absolute path to include a sniff. + * + * @covers \PHP_CodeSniffer\Ruleset + * @requires OS ^WIN.*. + * @group Windows + */ +final class RuleInclusionAbsoluteWindowsTest extends TestCase { /** @@ -41,21 +48,12 @@ class RuleInclusionAbsoluteWindowsTest extends TestCase /** * Initialize the config and ruleset objects. * + * @before + * * @return void */ - public function setUp() + protected function initializeConfigAndRuleset() { - if (DIRECTORY_SEPARATOR === '/') { - $this->markTestSkipped('Windows specific test'); - } - - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - $this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; $repoRootDir = dirname(dirname(dirname(__DIR__))); @@ -70,24 +68,24 @@ public function setUp() } // Initialize the config and ruleset objects for the test. - $config = new Config(["--standard={$this->standard}"]); + $config = new ConfigDouble(["--standard={$this->standard}"]); $this->ruleset = new Ruleset($config); - }//end setUp() + }//end initializeConfigAndRuleset() /** * Reset ruleset file. * + * @after + * * @return void */ - public function tearDown() + protected function resetRuleset() { - if (DIRECTORY_SEPARATOR !== '/') { - file_put_contents($this->standard, $this->contents); - } + file_put_contents($this->standard, $this->contents); - }//end tearDown() + }//end resetRuleset() /** @@ -99,7 +97,6 @@ public function tearDown() public function testWindowsStylePathRuleInclusion() { // Test that the sniff is correctly registered. - $this->assertObjectHasAttribute('sniffCodes', $this->ruleset); $this->assertCount(1, $this->ruleset->sniffCodes); $this->assertArrayHasKey('Generic.Formatting.SpaceAfterCast', $this->ruleset->sniffCodes); $this->assertSame( diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml index 15710d209..e92c68842 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml index ca116d45e..d95af20d9 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php index 24abe8dab..d91a6c259 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php @@ -4,16 +4,21 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Ruleset; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; -use PHPUnit\Framework\TestCase; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; -class RuleInclusionTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Ruleset class. + * + * @covers \PHP_CodeSniffer\Ruleset + */ +final class RuleInclusionTest extends AbstractRulesetTestCase { /** @@ -38,72 +43,56 @@ class RuleInclusionTest extends TestCase private static $contents = ''; - /** - * Initialize the test. - * - * @return void - */ - public function setUp() - { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - - }//end setUp() - - /** * Initialize the config and ruleset objects based on the `RuleInclusionTest.xml` ruleset file. * + * @before + * * @return void */ - public static function setUpBeforeClass() + protected function initializeConfigAndRuleset() { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // This test will be skipped. - return; - } - - $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; - self::$standard = $standard; + if (self::$standard === '') { + $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; + self::$standard = $standard; - // On-the-fly adjust the ruleset test file to be able to test - // sniffs included with relative paths. - $contents = file_get_contents($standard); - self::$contents = $contents; + // On-the-fly adjust the ruleset test file to be able to test + // sniffs included with relative paths. + $contents = file_get_contents($standard); + self::$contents = $contents; - $repoRootDir = basename(dirname(dirname(dirname(__DIR__)))); + $repoRootDir = basename(dirname(dirname(dirname(__DIR__)))); - $newPath = $repoRootDir; - if (DIRECTORY_SEPARATOR === '\\') { - $newPath = str_replace('\\', '/', $repoRootDir); - } + $newPath = $repoRootDir; + if (DIRECTORY_SEPARATOR === '\\') { + $newPath = str_replace('\\', '/', $repoRootDir); + } - $adjusted = str_replace('%path_root_dir%', $newPath, $contents); + $adjusted = str_replace('%path_root_dir%', $newPath, $contents); - if (file_put_contents($standard, $adjusted) === false) { - self::markTestSkipped('On the fly ruleset adjustment failed'); - } + if (file_put_contents($standard, $adjusted) === false) { + self::markTestSkipped('On the fly ruleset adjustment failed'); + } - $config = new Config(["--standard=$standard"]); - self::$ruleset = new Ruleset($config); + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + }//end if - }//end setUpBeforeClass() + }//end initializeConfigAndRuleset() /** * Reset ruleset file. * + * @after + * * @return void */ - public function tearDown() + public function resetRuleset() { file_put_contents(self::$standard, self::$contents); - }//end tearDown() + }//end resetRuleset() /** @@ -113,14 +102,13 @@ public function tearDown() */ public function testHasSniffCodes() { - $this->assertObjectHasAttribute('sniffCodes', self::$ruleset); - $this->assertCount(14, self::$ruleset->sniffCodes); + $this->assertCount(49, self::$ruleset->sniffCodes); }//end testHasSniffCodes() /** - * Test that sniffs are correctly registered, independently on the syntax used to include the sniff. + * Test that sniffs are correctly registered, independently of the syntax used to include the sniff. * * @param string $key Expected array key. * @param string $value Expected array value. @@ -142,11 +130,59 @@ public function testRegisteredSniffCodes($key, $value) * * @see self::testRegisteredSniffCodes() * - * @return array + * @return array> */ - public function dataRegisteredSniffCodes() + public static function dataRegisteredSniffCodes() { return [ + [ + 'PSR2.Classes.ClassDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff', + ], + [ + 'PSR2.Classes.PropertyDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\PropertyDeclarationSniff', + ], + [ + 'PSR2.ControlStructures.ControlStructureSpacing', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\ControlStructureSpacingSniff', + ], + [ + 'PSR2.ControlStructures.ElseIfDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\ElseIfDeclarationSniff', + ], + [ + 'PSR2.ControlStructures.SwitchDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\SwitchDeclarationSniff', + ], + [ + 'PSR2.Files.ClosingTag', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Files\ClosingTagSniff', + ], + [ + 'PSR2.Files.EndFileNewline', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Files\EndFileNewlineSniff', + ], + [ + 'PSR2.Methods.FunctionCallSignature', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff', + ], + [ + 'PSR2.Methods.FunctionClosingBrace', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionClosingBraceSniff', + ], + [ + 'PSR2.Methods.MethodDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\MethodDeclarationSniff', + ], + [ + 'PSR2.Namespaces.NamespaceDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Namespaces\NamespaceDeclarationSniff', + ], + [ + 'PSR2.Namespaces.UseDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Namespaces\UseDeclarationSniff', + ], [ 'PSR1.Classes.ClassDeclaration', 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', @@ -180,8 +216,100 @@ public function dataRegisteredSniffCodes() 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\UpperCaseConstantNameSniff', ], [ - 'Zend.NamingConventions.ValidVariableName', - 'PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff', + 'Generic.Files.LineEndings', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineEndingsSniff', + ], + [ + 'Generic.Files.LineLength', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', + ], + [ + 'Squiz.WhiteSpace.SuperfluousWhitespace', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SuperfluousWhitespaceSniff', + ], + [ + 'Generic.Formatting.DisallowMultipleStatements', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting\DisallowMultipleStatementsSniff', + ], + [ + 'Generic.WhiteSpace.ScopeIndent', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff', + ], + [ + 'Generic.WhiteSpace.DisallowTabIndent', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\DisallowTabIndentSniff', + ], + [ + 'Generic.PHP.LowerCaseKeyword', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseKeywordSniff', + ], + [ + 'Generic.PHP.LowerCaseConstant', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseConstantSniff', + ], + [ + 'Squiz.Scope.MethodScope', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\MethodScopeSniff', + ], + [ + 'Squiz.WhiteSpace.ScopeKeywordSpacing', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeKeywordSpacingSniff', + ], + [ + 'Squiz.Functions.FunctionDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\FunctionDeclarationSniff', + ], + [ + 'Squiz.Functions.LowercaseFunctionKeywords', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\LowercaseFunctionKeywordsSniff', + ], + [ + 'Squiz.Functions.FunctionDeclarationArgumentSpacing', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\FunctionDeclarationArgumentSpacingSniff', + ], + [ + 'PEAR.Functions.ValidDefaultValue', + 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\ValidDefaultValueSniff', + ], + [ + 'Squiz.Functions.MultiLineFunctionDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\MultiLineFunctionDeclarationSniff', + ], + [ + 'Generic.Functions.FunctionCallArgumentSpacing', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Functions\FunctionCallArgumentSpacingSniff', + ], + [ + 'Squiz.ControlStructures.ControlSignature', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ControlSignatureSniff', + ], + [ + 'Squiz.WhiteSpace.ControlStructureSpacing', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ControlStructureSpacingSniff', + ], + [ + 'Squiz.WhiteSpace.ScopeClosingBrace', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeClosingBraceSniff', + ], + [ + 'Squiz.ControlStructures.ForEachLoopDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ForEachLoopDeclarationSniff', + ], + [ + 'Squiz.ControlStructures.ForLoopDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ForLoopDeclarationSniff', + ], + [ + 'Squiz.ControlStructures.LowercaseDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\LowercaseDeclarationSniff', + ], + [ + 'Generic.ControlStructures.InlineControlStructure', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\ControlStructures\InlineControlStructureSniff', + ], + [ + 'PSR12.Operators.OperatorSpacing', + 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', ], [ 'Generic.Arrays.ArrayIndent', @@ -192,8 +320,8 @@ public function dataRegisteredSniffCodes() 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', ], [ - 'Generic.Files.LineLength', - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', + 'Squiz.Files.FileExtension', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff', ], [ 'Generic.NamingConventions.CamelCapsFunctionName', @@ -212,9 +340,9 @@ public function dataRegisteredSniffCodes() * Test that setting properties for standards, categories, sniffs works for all supported rule * inclusion methods. * - * @param string $sniffClass The name of the sniff class. - * @param string $propertyName The name of the changed property. - * @param mixed $expectedValue The value expected for the property. + * @param string $sniffClass The name of the sniff class. + * @param string $propertyName The name of the changed property. + * @param string|int|bool $expectedValue The value expected for the property. * * @dataProvider dataSettingProperties * @@ -222,9 +350,8 @@ public function dataRegisteredSniffCodes() */ public function testSettingProperties($sniffClass, $propertyName, $expectedValue) { - $this->assertObjectHasAttribute('sniffs', self::$ruleset); $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs); - $this->assertObjectHasAttribute($propertyName, self::$ruleset->sniffs[$sniffClass]); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]); $actualValue = self::$ruleset->sniffs[$sniffClass]->$propertyName; $this->assertSame($expectedValue, $actualValue); @@ -237,61 +364,116 @@ public function testSettingProperties($sniffClass, $propertyName, $expectedValue * * @see self::testSettingProperties() * - * @return array + * @return array> */ - public function dataSettingProperties() + public static function dataSettingProperties() { return [ - 'ClassDeclarationSniff' => [ - 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', - 'setforallsniffs', - true, + 'Set property for complete standard: PSR2 ClassDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff', + 'propertyName' => 'indent', + 'expectedValue' => '20', ], - 'SideEffectsSniff' => [ - 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Files\SideEffectsSniff', - 'setforallsniffs', - true, + 'Set property for complete standard: PSR2 SwitchDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\SwitchDeclarationSniff', + 'propertyName' => 'indent', + 'expectedValue' => '20', ], - 'ValidVariableNameSniff' => [ - 'PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff', - 'setforallincategory', - true, + 'Set property for complete standard: PSR2 FunctionCallSignature' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff', + 'propertyName' => 'indent', + 'expectedValue' => '20', ], - 'ArrayIndentSniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff', - 'indent', - '2', + 'Set property for complete category: PSR12 OperatorSpacing' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', + 'propertyName' => 'ignoreSpacingBeforeAssignments', + 'expectedValue' => false, ], - 'LineLengthSniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', - 'lineLimit', - '10', + 'Set property for individual sniff: Generic ArrayIndent' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff', + 'propertyName' => 'indent', + 'expectedValue' => '2', ], - 'CamelCapsFunctionNameSniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff', - 'strict', - false, + 'Set property for individual sniff using sniff file inclusion: Generic LineLength' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', + 'propertyName' => 'lineLimit', + 'expectedValue' => '10', ], - 'NestingLevelSniff-nestingLevel' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', - 'nestingLevel', - '2', + 'Set property for individual sniff using sniff file inclusion: CamelCapsFunctionName' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff', + 'propertyName' => 'strict', + 'expectedValue' => false, ], - 'NestingLevelSniff-setforsniffsinincludedruleset' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', - 'setforsniffsinincludedruleset', - true, + 'Set property for individual sniff via included ruleset: NestingLevel - nestingLevel' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', + 'propertyName' => 'nestingLevel', + 'expectedValue' => '2', + ], + 'Set property for all sniffs in an included ruleset: NestingLevel - absoluteNestingLevel' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', + 'propertyName' => 'absoluteNestingLevel', + 'expectedValue' => true, ], // Testing that setting a property at error code level does *not* work. - 'CyclomaticComplexitySniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', - 'complexity', - 10, + 'Set property for error code will not change the sniff property value: CyclomaticComplexity' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', + 'propertyName' => 'complexity', + 'expectedValue' => 10, ], ]; }//end dataSettingProperties() + /** + * Test that setting properties for standards, categories on sniffs which don't support the property will + * silently ignore the property and not set it. + * + * @param string $sniffClass The name of the sniff class. + * @param string $propertyName The name of the property which should not be set. + * + * @dataProvider dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails + * + * @return void + */ + public function testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails($sniffClass, $propertyName) + { + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + $this->assertXObjectNotHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]); + + }//end testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + + + /** + * Data provider. + * + * @see self::testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + * + * @return array> + */ + public static function dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + { + return [ + 'Set property for complete standard: PSR2 ClassDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', + 'propertyName' => 'setforallsniffs', + ], + 'Set property for complete standard: PSR2 FunctionCallSignature' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff', + 'propertyName' => 'setforallsniffs', + ], + 'Set property for complete category: PSR12 OperatorSpacing' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', + 'propertyName' => 'setforallincategory', + ], + 'Set property for all sniffs in included category directory' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff', + 'propertyName' => 'setforsquizfilessniffs', + ], + ]; + + }//end dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml index 06ce040e7..6b5c0a970 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml @@ -1,15 +1,17 @@ - + - + + - + + @@ -25,6 +27,14 @@ + + + + + + + + @@ -37,9 +47,11 @@ + + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml new file mode 100644 index 000000000..88eaa5ebf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml new file mode 100644 index 000000000..e8502e7ff --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml new file mode 100644 index 000000000..bfbfaf5e6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml new file mode 100644 index 000000000..67fcca351 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml new file mode 100644 index 000000000..a678c9155 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml new file mode 100644 index 000000000..8ce97e2dd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml new file mode 100644 index 000000000..c6a14c259 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml new file mode 100644 index 000000000..a1742618a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php new file mode 100644 index 000000000..b9d9ac1f2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php @@ -0,0 +1,421 @@ + + * @copyright 2022 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use ReflectionObject; + +/** + * These tests specifically focus on the changes made to work around the PHP 8.2 dynamic properties deprecation. + * + * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty + */ +final class SetSniffPropertyTest extends AbstractRulesetTestCase +{ + + + /** + * Test that setting a property via the ruleset works in all situations which allow for it. + * + * @param string $name Name of the test. Used for the sniff name, the ruleset file name etc. + * + * @dataProvider dataSniffPropertiesGetSetWhenAllowed + * + * @return void + */ + public function testSniffPropertiesGetSetWhenAllowed($name) + { + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; + $properties = [ + 'arbitrarystring' => 'arbitraryvalue', + 'arbitraryarray' => [ + 'mykey' => 'myvalue', + 'otherkey' => 'othervalue', + ], + ]; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that the sniff has been registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class'); + + // Test that the property as declared in the ruleset has been set on the sniff. + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[$sniffClass]; + foreach ($properties as $name => $expectedValue) { + $this->assertSame($expectedValue, $sniffObject->$name, 'Property value not set to expected value'); + } + + }//end testSniffPropertiesGetSetWhenAllowed() + + + /** + * Data provider. + * + * @see self::testSniffPropertiesGetSetWhenAllowed() + * + * @return array> + */ + public static function dataSniffPropertiesGetSetWhenAllowed() + { + return [ + 'Property allowed as explicitly declared' => ['AllowedAsDeclared'], + 'Property allowed as sniff extends stdClass' => ['AllowedViaStdClass'], + 'Property allowed as sniff has magic __set() method' => ['AllowedViaMagicMethod'], + ]; + + }//end dataSniffPropertiesGetSetWhenAllowed() + + + /** + * Test that setting a property for a category will apply it correctly to those sniffs which support the + * property, but won't apply it to sniffs which don't. + * + * Note: this test intentionally uses the `PEAR.Functions` category as two sniffs in that category + * have a public property with the same name (`indent`) and one sniff doesn't, which makes it a great + * test case for this. + * + * @return void + */ + public function testSetPropertyAppliesPropertyToMultipleSniffsInCategory() + { + $propertyName = 'indent'; + $expectedValue = '10'; + + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Test that the two sniffs which support the property have received the value. + $sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionCallSignatureSniff'; + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($expectedValue, $sniffObject->$propertyName, 'Property value not set to expected value for '.$sniffClass); + + $sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionDeclarationSniff'; + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($expectedValue, $sniffObject->$propertyName, 'Property value not set to expected value for '.$sniffClass); + + // Test that the property doesn't get set for the one sniff which doesn't support the property. + $sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\ValidDefaultValueSniff'; + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + + $hasProperty = (new ReflectionObject($ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); + $errorMsg = sprintf('Property %s registered for sniff %s which does not support it', $propertyName, $sniffClass); + $this->assertFalse($hasProperty, $errorMsg); + + }//end testSetPropertyAppliesPropertyToMultipleSniffsInCategory() + + + /** + * Test that attempting to set a non-existent property directly on a sniff will throw an error + * when the sniff does not explicitly declare the property, extends stdClass or has magic methods. + * + * @return void + */ + public function testSetPropertyThrowsErrorOnInvalidProperty() + { + $exceptionMsg = 'ERROR: Property "indentation" does not exist on sniff Generic.Arrays.ArrayIndent.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($exceptionMsg); + + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyThrowsErrorOnInvalidPropertyTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testSetPropertyThrowsErrorOnInvalidProperty() + + + /** + * Test that attempting to set a non-existent property directly on a sniff will throw an error + * when the sniff does not explicitly declare the property, extends stdClass or has magic methods, + * even though the sniff has the PHP 8.2 `#[AllowDynamicProperties]` attribute set. + * + * @return void + */ + public function testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() + { + $exceptionMsg = 'ERROR: Property "arbitrarystring" does not exist on sniff TestStandard.SetProperty.NotAllowedViaAttribute.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($exceptionMsg); + + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyNotAllowedViaAttributeTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() + + + /** + * Test that attempting to set a non-existent property on a sniff when the property directive is + * for the whole standard, does not yield an error. + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandard() + { + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandard() + + + /** + * Test that attempting to set a non-existent property on a sniff when the property directive is + * for a whole category, does not yield an error. + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory() + { + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory() + + + /** + * Test that attempting to set a property for a sniff which isn't registered will be ignored. + * + * @return void + */ + public function testDirectCallIgnoredPropertyForUnusedSniff() + { + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Formatting\\SpaceAfterCastSniff'; + + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1']); + $ruleset = new Ruleset($config); + + $ruleset->setSniffProperty( + $sniffClass, + 'ignoreNewlines', + [ + 'scope' => 'sniff', + 'value' => true, + ] + ); + + // Verify that there are sniffs registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has NOT been registered after attempting to set the property. + $this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, 'Unused sniff was registered in sniffCodes, but shouldn\'t have been'); + $this->assertArrayNotHasKey($sniffClass, $ruleset->sniffs, 'Unused sniff was registered in sniffs, but shouldn\'t have been'); + + }//end testDirectCallIgnoredPropertyForUnusedSniff() + + + /** + * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method + * sets the property correctly when using the new $settings array format. + * + * @return void + */ + public function testDirectCallWithNewArrayFormatSetsProperty() + { + $name = 'AllowedAsDeclared'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $propertyName = 'arbitrarystring'; + $propertyValue = 'new value'; + + $ruleset->setSniffProperty( + $sniffClass, + $propertyName, + [ + 'scope' => 'sniff', + 'value' => $propertyValue, + ] + ); + + // Verify that the sniff has been registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class'); + + // Test that the property as declared in the ruleset has been set on the sniff. + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value'); + + }//end testDirectCallWithNewArrayFormatSetsProperty() + + + /** + * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method + * sets the property correctly when using the old $settings array format. + * + * Tested by silencing the deprecation notice as otherwise the test would fail on the deprecation notice. + * + * @param mixed $propertyValue Value for the property to set. + * + * @dataProvider dataDirectCallWithOldArrayFormatSetsProperty + * + * @return void + */ + public function testDirectCallWithOldArrayFormatSetsProperty($propertyValue) + { + $name = 'AllowedAsDeclared'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $propertyName = 'arbitrarystring'; + + @$ruleset->setSniffProperty( + $sniffClass, + $propertyName, + $propertyValue + ); + + // Verify that the sniff has been registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class'); + + // Test that the property as declared in the ruleset has been set on the sniff. + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value'); + + }//end testDirectCallWithOldArrayFormatSetsProperty() + + + /** + * Data provider. + * + * @see self::testDirectCallWithOldArrayFormatSetsProperty() + * + * @return array> + */ + public static function dataDirectCallWithOldArrayFormatSetsProperty() + { + return [ + 'Property value is not an array (boolean)' => [ + 'propertyValue' => false, + ], + 'Property value is not an array (string)' => [ + 'propertyValue' => 'a string', + ], + 'Property value is an empty array' => [ + 'propertyValue' => [], + ], + 'Property value is an array without keys' => [ + 'propertyValue' => [ + 'value', + false, + ], + ], + 'Property value is an array without the "scope" or "value" keys' => [ + 'propertyValue' => [ + 'key1' => 'value', + 'key2' => false, + ], + ], + 'Property value is an array without the "scope" key' => [ + 'propertyValue' => [ + 'key1' => 'value', + 'value' => true, + ], + ], + 'Property value is an array without the "value" key' => [ + 'propertyValue' => [ + 'scope' => 'value', + 'key2' => 1234, + ], + ], + ]; + + }//end dataDirectCallWithOldArrayFormatSetsProperty() + + + /** + * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method + * throws a deprecation notice when using the old $settings array format. + * + * Note: as PHPUnit stops as soon as it sees the deprecation notice, the setting of the property + * value is not tested here. + * + * @return void + */ + public function testDirectCallWithOldArrayFormatThrowsDeprecationNotice() + { + $exceptionClass = 'PHPUnit\Framework\Error\Deprecated'; + if (class_exists($exceptionClass) === false) { + $exceptionClass = 'PHPUnit_Framework_Error_Deprecated'; + } + + $exceptionMsg = 'the format of the $settings parameter has changed from (mixed) $value to array(\'scope\' => \'sniff|standard\', \'value\' => $value). Please update your integration code. See PR #3629 for more information.'; + + if (method_exists($this, 'expectException') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedException($exceptionClass, $exceptionMsg); + } + + $name = 'AllowedAsDeclared'; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $ruleset->setSniffProperty( + $sniffClass, + 'arbitrarystring', + ['key' => 'value'] + ); + + }//end testDirectCallWithOldArrayFormatThrowsDeprecationNotice() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml new file mode 100644 index 000000000..75527e2b1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml new file mode 100644 index 000000000..150fc3e52 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml new file mode 100644 index 000000000..973e065a1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml new file mode 100644 index 000000000..493adfd1e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml new file mode 100644 index 000000000..358cb0df5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml new file mode 100644 index 000000000..fbc0cb7b7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml new file mode 100644 index 000000000..86cc615c4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php new file mode 100644 index 000000000..db793fdeb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -0,0 +1,540 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Tests PHPCS native handling of sniff deprecations. + * + * @covers \PHP_CodeSniffer\Ruleset::hasSniffDeprecations + * @covers \PHP_CodeSniffer\Ruleset::showSniffDeprecations + */ +final class ShowSniffDeprecationsTest extends AbstractRulesetTestCase +{ + + + /** + * Test the return value of the hasSniffDeprecations() method. + * + * @param string $standard The standard to use for the test. + * @param bool $expected The expected function return value. + * + * @dataProvider dataHasSniffDeprecations + * + * @return void + */ + public function testHasSniffDeprecations($standard, $expected) + { + $config = new ConfigDouble(['.', "--standard=$standard"]); + $ruleset = new Ruleset($config); + + $this->assertSame($expected, $ruleset->hasSniffDeprecations()); + + }//end testHasSniffDeprecations() + + + /** + * Data provider. + * + * @see testHasSniffDeprecations() + * + * @return array> + */ + public static function dataHasSniffDeprecations() + { + return [ + 'Standard not using deprecated sniffs: PSR1' => [ + 'standard' => 'PSR1', + 'expected' => false, + ], + 'Standard using deprecated sniffs: Test Fixture' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'expected' => true, + ], + ]; + + }//end dataHasSniffDeprecations() + + + /** + * Test that the listing with deprecated sniffs will not show when specific command-line options are being used [1]. + * + * @param string $standard The standard to use for the test. + * @param array $additionalArgs Optional. Additional arguments to pass. + * + * @dataProvider dataDeprecatedSniffsListDoesNotShow + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs=[]) + { + $args = $additionalArgs; + $args[] = '.'; + $args[] = "--standard=$standard"; + + $config = new ConfigDouble($args); + $ruleset = new Ruleset($config); + + $this->expectOutputString(''); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsListDoesNotShow() + + + /** + * Data provider. + * + * @see testDeprecatedSniffsListDoesNotShow() + * + * @return array>> + */ + public static function dataDeprecatedSniffsListDoesNotShow() + { + return [ + 'Standard not using deprecated sniffs: PSR1' => [ + 'standard' => 'PSR1', + ], + 'Standard using deprecated sniffs; explain mode' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'additionalArgs' => ['-e'], + ], + 'Standard using deprecated sniffs; quiet mode' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'additionalArgs' => ['-q'], + ], + ]; + + }//end dataDeprecatedSniffsListDoesNotShow() + + + /** + * Test that the listing with deprecated sniffs will not show when specific command-line options are being used [2]. + * + * {@internal Separate test method for the same thing as this test will only work in CS mode.} + * + * @param string $standard The standard to use for the test. + * @param array $additionalArgs Optional. Additional arguments to pass. + * + * @dataProvider dataDeprecatedSniffsListDoesNotShowNeedsCsMode + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShowNeedsCsMode($standard, $additionalArgs=[]) + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs); + + }//end testDeprecatedSniffsListDoesNotShowNeedsCsMode() + + + /** + * Data provider. + * + * @see testDeprecatedSniffsListDoesNotShowNeedsCsMode() + * + * @return array>> + */ + public static function dataDeprecatedSniffsListDoesNotShowNeedsCsMode() + { + return [ + 'Standard using deprecated sniffs; documentation is requested' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'additionalArgs' => ['--generator=text'], + ], + ]; + + }//end dataDeprecatedSniffsListDoesNotShowNeedsCsMode() + + + /** + * Test that the listing with deprecated sniffs will not show when using a standard containing deprecated sniffs, + * but only running select non-deprecated sniffs (using `--sniffs=...`). + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDeprecated() + { + $standard = __DIR__.'/ShowSniffDeprecationsTest.xml'; + $config = new ConfigDouble(['.', "--standard=$standard"]); + $ruleset = new Ruleset($config); + + /* + * Apply sniff restrictions. + * For tests we need to manually trigger this if the standard is "installed", like with the fixtures these tests use. + */ + + $restrictions = []; + $sniffs = [ + 'TestStandard.SetProperty.AllowedAsDeclared', + 'TestStandard.SetProperty.AllowedViaStdClass', + ]; + foreach ($sniffs as $sniffCode) { + $parts = explode('.', strtolower($sniffCode)); + $sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $restrictions[strtolower($sniffName)] = true; + } + + $sniffFiles = []; + $allSniffs = $ruleset->sniffCodes; + foreach ($allSniffs as $sniffName) { + $sniffFile = str_replace('\\', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.$sniffFile.'.php'; + $sniffFiles[] = $sniffFile; + } + + $ruleset->registerSniffs($sniffFiles, $restrictions, []); + $ruleset->populateTokenListeners(); + + $this->expectOutputString(''); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDeprecated() + + + /** + * Test that the listing with deprecated sniffs will not show when using a standard containing deprecated sniffs, + * but all deprecated sniffs have been excluded from the run (using `--exclude=...`). + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExcluded() + { + $standard = __DIR__.'/ShowSniffDeprecationsTest.xml'; + $config = new ConfigDouble(['.', "--standard=$standard"]); + $ruleset = new Ruleset($config); + + /* + * Apply sniff restrictions. + * For tests we need to manually trigger this if the standard is "installed", like with the fixtures these tests use. + */ + + $exclusions = []; + $exclude = [ + 'TestStandard.Deprecated.WithLongReplacement', + 'TestStandard.Deprecated.WithoutReplacement', + 'TestStandard.Deprecated.WithReplacement', + 'TestStandard.Deprecated.WithReplacementContainingLinuxNewlines', + 'TestStandard.Deprecated.WithReplacementContainingNewlines', + ]; + foreach ($exclude as $sniffCode) { + $parts = explode('.', strtolower($sniffCode)); + $sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $exclusions[strtolower($sniffName)] = true; + } + + $sniffFiles = []; + $allSniffs = $ruleset->sniffCodes; + foreach ($allSniffs as $sniffName) { + $sniffFile = str_replace('\\', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.$sniffFile.'.php'; + $sniffFiles[] = $sniffFile; + } + + $ruleset->registerSniffs($sniffFiles, [], $exclusions); + $ruleset->populateTokenListeners(); + + $this->expectOutputString(''); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExcluded() + + + /** + * Test various aspects of the deprecated sniffs warning. + * + * This tests a number of different aspects: + * 1. That the summary line uses the correct grammar when there is are multiple deprecated sniffs. + * 2. That there is no trailing whitespace when the sniff does not provide a custom message. + * 3. That custom messages containing new line characters (any type) are handled correctly and + * that those new line characters are converted to the OS supported new line char. + * + * @return void + */ + public function testDeprecatedSniffsWarning() + { + $standard = __DIR__.'/ShowSniffDeprecationsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '--no-colors']); + $ruleset = new Ruleset($config); + + $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 5 deprecated sniffs'.PHP_EOL; + $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL; + $expected .= ' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL; + $expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In'.PHP_EOL; + $expected .= ' lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL; + $expected .= ' eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat.'.PHP_EOL; + $expected .= ' Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt'.PHP_EOL; + $expected .= ' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL; + $expected .= ' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL; + $expected .= ' libero.'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacementContainingLinuxNewlines'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; + $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; + $expected .= ' sed.'.PHP_EOL; + $expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus.'.PHP_EOL; + $expected .= ' In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL; + $expected .= ' eros sapien at sem.'.PHP_EOL; + $expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL; + $expected .= ' lectus at egestas.'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacementContainingNewlines'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; + $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; + $expected .= ' sed.'.PHP_EOL; + $expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus.'.PHP_EOL; + $expected .= ' In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL; + $expected .= ' eros sapien at sem.'.PHP_EOL; + $expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL; + $expected .= ' lectus at egestas'.PHP_EOL.PHP_EOL; + $expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL; + $expected .= 'future.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsWarning() + + + /** + * Test the report width is respected when displaying the deprecated sniffs warning. + * + * This tests the following aspects: + * 1. That the summary line uses the correct grammar when there is a single deprecated sniff. + * 2. That the separator line below the summary maximizes at the longest line length. + * 3. That the word wrapping respects the maximum report width. + * 4. That the sniff name is truncated if it is longer than the max report width. + * + * @param int $reportWidth Report width for the test. + * @param string $expectedOutput Expected output. + * + * @dataProvider dataReportWidthIsRespected + * + * @return void + */ + public function testReportWidthIsRespected($reportWidth, $expectedOutput) + { + // Set up the ruleset. + $standard = __DIR__.'/ShowSniffDeprecationsReportWidthTest.xml'; + $config = new ConfigDouble(['.', "--standard=$standard", "--report-width=$reportWidth", '--no-colors']); + $ruleset = new Ruleset($config); + + $this->expectOutputString($expectedOutput); + + $ruleset->showSniffDeprecations(); + + }//end testReportWidthIsRespected() + + + /** + * Data provider. + * + * @see testReportWidthIsRespected() + * + * @return array> + */ + public static function dataReportWidthIsRespected() + { + $summaryLine = 'WARNING: The ShowSniffDeprecationsTest standard uses 1 deprecated sniff'.PHP_EOL; + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Report width small: 40; with truncated sniff name and wrapped header and footer lines' => [ + 'reportWidth' => 40, + 'expectedOutput' => 'WARNING: The ShowSniffDeprecationsTest'.PHP_EOL + .'standard uses 1 deprecated sniff'.PHP_EOL + .'----------------------------------------'.PHP_EOL + .'- TestStandard.Deprecated.WithLongR...'.PHP_EOL + .' This sniff has been deprecated since'.PHP_EOL + .' v3.8.0 and will be removed in'.PHP_EOL + .' v4.0.0. Lorem ipsum dolor sit amet,'.PHP_EOL + .' consectetur adipiscing elit. Fusce'.PHP_EOL + .' vel vestibulum nunc. Sed luctus'.PHP_EOL + .' dolor tortor, eu euismod purus'.PHP_EOL + .' pretium sed. Fusce egestas congue'.PHP_EOL + .' massa semper cursus. Donec quis'.PHP_EOL + .' pretium tellus. In lacinia, augue ut'.PHP_EOL + .' ornare porttitor, diam nunc faucibus'.PHP_EOL + .' purus, et accumsan eros sapien at'.PHP_EOL + .' sem. Sed pulvinar aliquam malesuada.'.PHP_EOL + .' Aliquam erat volutpat. Mauris'.PHP_EOL + .' gravida rutrum lectus at egestas.'.PHP_EOL + .' Fusce tempus elit in tincidunt'.PHP_EOL + .' dictum. Suspendisse dictum egestas'.PHP_EOL + .' sapien, eget ullamcorper metus'.PHP_EOL + .' elementum semper. Vestibulum sem'.PHP_EOL + .' justo, consectetur ac tincidunt et,'.PHP_EOL + .' finibus eget libero.'.PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but'.PHP_EOL + .'will stop working at some point in the'.PHP_EOL + .'future.'.PHP_EOL.PHP_EOL, + ], + 'Report width default: 80' => [ + 'reportWidth' => 80, + 'expectedOutput' => $summaryLine.str_repeat('-', 80).PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL + .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL + .' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL + .' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL + .' Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In'.PHP_EOL + .' lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL + .' eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat.'.PHP_EOL + .' Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt'.PHP_EOL + .' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL + .' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL + .' libero.'.PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL + .'future.'.PHP_EOL.PHP_EOL, + ], + 'Report width matches longest line: 666; the message should not wrap' => [ + // Length = 4 padding + 75 base line + 587 custom message. + 'reportWidth' => 666, + 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL + .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' + .PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, + ], + 'Report width wide: 1000; delimiter line length should match longest line' => [ + 'reportWidth' => 1000, + 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL + .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' + .PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataReportWidthIsRespected() + + + /** + * Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning. + * + * Additionally, this test verifies that deprecated sniffs are still registered to run. + * + * @return void + */ + public function testDeprecatedSniffsAreListedAlphabetically() + { + // Set up the ruleset. + $standard = __DIR__.'/ShowSniffDeprecationsOrderTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '--no-colors']); + $ruleset = new Ruleset($config); + + $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 2 deprecated sniffs'.PHP_EOL; + $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL.PHP_EOL; + $expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL; + $expected .= 'future.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->showSniffDeprecations(); + + // Verify that the sniffs have been registered to run. + $this->assertCount(2, $ruleset->sniffCodes, 'Incorrect number of sniff codes registered'); + $this->assertArrayHasKey( + 'TestStandard.Deprecated.WithoutReplacement', + $ruleset->sniffCodes, + 'WithoutReplacement sniff not registered' + ); + $this->assertArrayHasKey( + 'TestStandard.Deprecated.WithReplacement', + $ruleset->sniffCodes, + 'WithReplacement sniff not registered' + ); + + }//end testDeprecatedSniffsAreListedAlphabetically() + + + /** + * Test that an exception is thrown when any of the interface required methods does not + * comply with the return type/value requirements. + * + * @param string $standard The standard to use for the test. + * @param string $exceptionMessage The contents of the expected exception message. + * + * @dataProvider dataExceptionIsThrownOnIncorrectlyImplementedInterface + * + * @return void + */ + public function testExceptionIsThrownOnIncorrectlyImplementedInterface($standard, $exceptionMessage) + { + $this->expectRuntimeExceptionMessage($exceptionMessage); + + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $ruleset->showSniffDeprecations(); + + }//end testExceptionIsThrownOnIncorrectlyImplementedInterface() + + + /** + * Data provider. + * + * @see testExceptionIsThrownOnIncorrectlyImplementedInterface() + * + * @return array> + */ + public static function dataExceptionIsThrownOnIncorrectlyImplementedInterface() + { + return [ + 'getDeprecationVersion() does not return a string' => [ + 'standard' => 'ShowSniffDeprecationsInvalidDeprecationVersionTest.xml', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received double', + ], + 'getRemovalVersion() does not return a string' => [ + 'standard' => 'ShowSniffDeprecationsInvalidRemovalVersionTest.xml', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received array', + ], + 'getDeprecationMessage() does not return a string' => [ + 'standard' => 'ShowSniffDeprecationsInvalidDeprecationMessageTest.xml', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationMessageSniff::getDeprecationMessage() method must return a string, received object', + ], + 'getDeprecationVersion() returns an empty string' => [ + 'standard' => 'ShowSniffDeprecationsEmptyDeprecationVersionTest.xml', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received ""', + ], + 'getRemovalVersion() returns an empty string' => [ + 'standard' => 'ShowSniffDeprecationsEmptyRemovalVersionTest.xml', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received ""', + ], + ]; + + }//end dataExceptionIsThrownOnIncorrectlyImplementedInterface() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml new file mode 100644 index 000000000..ab632b195 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php new file mode 100644 index 000000000..ae5905bc6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php @@ -0,0 +1,19 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $this->checkProgressDot($colors, $code, $sniffs, $expected); + + }//end testProgressDotCs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataProgressDotCs() + { + return [ + 'No colors: Dot: no errors, no warnings' => [ + 'colors' => false, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'No colors: E: has error' => [ + 'colors' => false, + 'code' => ' 'Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence', + 'expected' => 'E', + ], + 'No colors: W: has warning' => [ + 'colors' => false, + 'code' => ' 'Generic.Commenting.Todo', + 'expected' => 'W', + ], + + 'Colors: Dot: no errors, no warnings' => [ + 'colors' => true, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'Colors: E: has error (red)' => [ + 'colors' => true, + 'code' => ' 'Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence', + 'expected' => "\033[31m".'E'."\033[0m", + ], + 'Colors: E: has fixable error (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => "\033[32m".'E'."\033[0m", + ], + 'Colors: W: has warning (yellow)' => [ + 'colors' => true, + 'code' => ' 'Generic.Commenting.Todo', + 'expected' => "\033[33m".'W'."\033[0m", + ], + 'Colors: W: has fixable warning (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.CodeAnalysis.EmptyPHPStatement', + 'expected' => "\033[32m".'W'."\033[0m", + ], + ]; + + }//end dataProgressDotCs() + + + /** + * Verify the correct progress indicator is used for a file in CBF mode. + * + * @param bool $colors Whether to enable colors or not. + * @param string $code Code snippet to process. + * @param string $sniffs Comma-separated list of sniff(s) to run against the code snippet. + * @param string $expected Expected output of the progress printer. + * + * @dataProvider dataProgressDotCbf + * + * @group CBF + * + * @return void + */ + public function testProgressDotCbf($colors, $code, $sniffs, $expected) + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->checkProgressDot($colors, $code, $sniffs, $expected, true); + + }//end testProgressDotCbf() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataProgressDotCbf() + { + return [ + 'No colors: Dot: no errors, no warnings' => [ + 'colors' => false, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'No colors: F: fixes made' => [ + 'colors' => false, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => 'F', + ], + 'No colors: E: has fixer conflict' => [ + 'colors' => false, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax,Generic.Arrays.DisallowShortArraySyntax', + 'expected' => 'E', + ], + + 'Colors: Dot: no errors, no warnings (no color)' => [ + 'colors' => true, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'Colors: F: fixes made (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => "\033[32m".'F'."\033[0m", + ], + 'Colors: E: has fixer conflict (red)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax,Generic.Arrays.DisallowShortArraySyntax', + 'expected' => "\033[31m".'E'."\033[0m", + ], + ]; + + }//end dataProgressDotCbf() + + + /** + * Verify the correct progress indicator is used for a file in CBF mode. + * + * @param bool $colors Whether to enable colors or not. + * @param string $code Code snippet to process. + * @param string $sniffs Comma-separated list of sniff(s) to run against the code snippet. + * @param string $expected Expected output of the progress printer. + * @param bool $enableFixer Whether to fix the code or not. + * + * @return void + */ + private function checkProgressDot($colors, $code, $sniffs, $expected, $enableFixer=false) + { + $this->expectOutputString($expected); + + $config = new ConfigDouble(['-p']); + $config->colors = $colors; + $config->standards = ['Generic']; + $config->sniffs = explode(',', $sniffs); + $ruleset = new Ruleset($config); + + $runner = new Runner(); + $runner->config = $config; + + $file = new DummyFile($code, $ruleset, $config); + $file->process(); + + if ($enableFixer === true) { + $file->fixer->fixFile(); + } + + $runner->printProgress($file, 2, 1); + + }//end checkProgressDot() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php new file mode 100644 index 000000000..93535417e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php @@ -0,0 +1,235 @@ +standards = ['Generic']; + self::$config->sniffs = ['Generic.PHP.LowerCaseConstant']; + self::$ruleset = new Ruleset(self::$config); + + self::$runner = new Runner(); + self::$runner->config = self::$config; + + // Simple file which won't have any errors against the above sniff. + $content = 'process(); + + }//end initializeConfigRulesetRunner() + + + /** + * Reset some flags between tests. + * + * @after + * + * @return void + */ + protected function resetObjectFlags() + { + self::$config->showProgress = true; + self::$fileWithoutErrorsOrWarnings->ignored = false; + + }//end resetObjectFlags() + + + /** + * Destroy the Config object after the test to reset statics. + * + * @afterClass + * + * @return void + */ + public static function reset() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when this object is destroyed, but we can't definitively rely on that). + self::$config->__destruct(); + + }//end reset() + + + /** + * Verify that if progress reporting is disabled, no progress dots will show. + * + * @return void + */ + public function testNoProgressIsShownWhenDisabled() + { + $this->expectOutputString(''); + + self::$config->showProgress = false; + + for ($i = 1; $i <= 10; $i++) { + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, 3, $i); + } + + }//end testNoProgressIsShownWhenDisabled() + + + /** + * Verify ignored files will be marked with an "S" for "skipped". + * + * @return void + */ + public function testProgressDotSkippedFiles() + { + $nrOfFiles = 10; + $this->expectOutputString('.S.S.S.S.S 10 / 10 (100%)'.PHP_EOL); + + for ($i = 1; $i <= $nrOfFiles; $i++) { + if (($i % 2) === 0) { + self::$fileWithoutErrorsOrWarnings->ignored = true; + } else { + self::$fileWithoutErrorsOrWarnings->ignored = false; + } + + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, $nrOfFiles, $i); + } + + }//end testProgressDotSkippedFiles() + + + /** + * Verify the handling of the summary at the end of each line. + * + * @param int $nrOfFiles The number of files in the scan. + * @param string $expected The expected progress information output. + * + * @dataProvider dataEndOfLineSummary + * + * @return void + */ + public function testEndOfLineSummary($nrOfFiles, $expected) + { + $this->expectOutputString($expected); + + for ($i = 1; $i <= $nrOfFiles; $i++) { + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, $nrOfFiles, $i); + } + + }//end testEndOfLineSummary() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataEndOfLineSummary() + { + $fullLineOfDots = str_repeat('.', 60); + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Favour test readability. + return [ + 'Less than 60 files (23)' => [ + 'nrOfFiles' => 23, + 'expected' => str_repeat('.', 23).' 23 / 23 (100%)'.PHP_EOL, + ], + 'Exactly 60 files' => [ + 'nrOfFiles' => 60, + 'expected' => $fullLineOfDots.' 60 / 60 (100%)'.PHP_EOL, + ], + 'Between 60 and 120 files (71)' => [ + 'nrOfFiles' => 71, + 'expected' => $fullLineOfDots.' 60 / 71 (85%)'.PHP_EOL + .str_repeat('.', 11).str_repeat(' ', 49).' 71 / 71 (100%)'.PHP_EOL, + ], + 'More than 120 files (162)' => [ + 'nrOfFiles' => 162, + 'expected' => $fullLineOfDots.' 60 / 162 (37%)'.PHP_EOL + .$fullLineOfDots.' 120 / 162 (74%)'.PHP_EOL + .str_repeat('.', 42).str_repeat(' ', 18).' 162 / 162 (100%)'.PHP_EOL, + ], + // More than anything, this tests that the padding of the numbers is handled correctly. + 'More than 1000 files (1234)' => [ + 'nrOfFiles' => 1234, + 'expected' => $fullLineOfDots.' 60 / 1234 (5%)'.PHP_EOL + .$fullLineOfDots.' 120 / 1234 (10%)'.PHP_EOL + .$fullLineOfDots.' 180 / 1234 (15%)'.PHP_EOL + .$fullLineOfDots.' 240 / 1234 (19%)'.PHP_EOL + .$fullLineOfDots.' 300 / 1234 (24%)'.PHP_EOL + .$fullLineOfDots.' 360 / 1234 (29%)'.PHP_EOL + .$fullLineOfDots.' 420 / 1234 (34%)'.PHP_EOL + .$fullLineOfDots.' 480 / 1234 (39%)'.PHP_EOL + .$fullLineOfDots.' 540 / 1234 (44%)'.PHP_EOL + .$fullLineOfDots.' 600 / 1234 (49%)'.PHP_EOL + .$fullLineOfDots.' 660 / 1234 (53%)'.PHP_EOL + .$fullLineOfDots.' 720 / 1234 (58%)'.PHP_EOL + .$fullLineOfDots.' 780 / 1234 (63%)'.PHP_EOL + .$fullLineOfDots.' 840 / 1234 (68%)'.PHP_EOL + .$fullLineOfDots.' 900 / 1234 (73%)'.PHP_EOL + .$fullLineOfDots.' 960 / 1234 (78%)'.PHP_EOL + .$fullLineOfDots.' 1020 / 1234 (83%)'.PHP_EOL + .$fullLineOfDots.' 1080 / 1234 (88%)'.PHP_EOL + .$fullLineOfDots.' 1140 / 1234 (92%)'.PHP_EOL + .$fullLineOfDots.' 1200 / 1234 (97%)'.PHP_EOL + .str_repeat('.', 34).str_repeat(' ', 26).' 1234 / 1234 (100%)'.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataEndOfLineSummary() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php new file mode 100644 index 000000000..479fe5ce9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php @@ -0,0 +1,73 @@ + + * @copyright 2023 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Runner; + +use PHP_CodeSniffer\Runner; +use PHP_CodeSniffer\Tests\Core\Runner\AbstractRunnerTestCase; + +/** + * Tests the wiring in of the explain functionality in the Runner class. + * + * @covers \PHP_CodeSniffer\Runner::runPHPCS + */ +final class RunPHPCSExplainTest extends AbstractRunnerTestCase +{ + + + /** + * Test that each standard passed on the command-line is explained separately. + * + * @return void + */ + public function testExplainWillExplainEachStandardSeparately() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $standard = dirname(__DIR__).'/Ruleset/ExplainSingleSniffTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '-e', + "--standard=PSR1,$standard", + '--report-width=80', + ]; + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL.PHP_EOL; + + $expected .= 'The ExplainSingleSniffTest standard contains 1 sniff'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $runner = new Runner(); + $runner->runPHPCS(); + + }//end testExplainWillExplainEachStandardSeparately() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php new file mode 100644 index 000000000..0bc89f220 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php @@ -0,0 +1,72 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $standard = dirname(__DIR__).'/Generators/OneDocTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '--generator=Text', + "--standard=$standard,PSR1", + '--report-width=80', + ]; + + $regex = '`^ + \R* # Optional blank line at the start. + (?: + (?P-++\R) # Line with dashes. + \|[ ]GENERATORTEST[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for first standard. + (?P>delimiter) # Line with dashes. + \R(?:[^\r\n]+\R)+\R{2} # Standard description. + ) # Only expect this group once. + (?: + (?P>delimiter) # Line with dashes. + \|[ ]PSR1[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for second standard. + (?P>delimiter) # Line with dashes. + \R(?:[^\r\n]+\R)+\R # Standard description. + (?: + -+[ ]CODE[ ]COMPARISON[ ]-+\R # Code Comparison starter line with dashes. + (?:(?:[^\r\n]+\R)+(?P>delimiter)){2} # Arbitrary text followed by a delimiter line. + )* # Code comparison is optional and can exist multiple times. + \R+ + ){3,} # This complete group should occur at least three times. + `x'; + + $this->expectOutputRegex($regex); + + $runner = new Runner(); + $runner->runPHPCS(); + + }//end testGeneratorWillShowEachStandardSeparately() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php index 20c28d60b..993603a53 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Sniffs; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class AbstractArraySniffTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Sniffs\AbstractArraySniff. + * + * @covers \PHP_CodeSniffer\Sniffs\AbstractArraySniff + */ +final class AbstractArraySniffTest extends AbstractMethodUnitTest { /** @@ -20,7 +25,7 @@ class AbstractArraySniffTest extends AbstractMethodUnitTest * This extends the \PHP_CodeSniffer\Sniffs\AbstractArraySniff class to make the * internal workings of the sniff observable. * - * @var \PHP_CodeSniffer\Sniffs\AbstractArraySniffTestable + * @var \PHP_CodeSniffer\Tests\Core\Sniffs\AbstractArraySniffTestable */ protected static $sniff; @@ -31,14 +36,16 @@ class AbstractArraySniffTest extends AbstractMethodUnitTest * The test case file for a unit test class has to be in the same directory * directory and use the same file name as the test class, using the .inc extension. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function initializeFile() { self::$sniff = new AbstractArraySniffTestable(); - parent::setUpBeforeClass(); + parent::initializeFile(); - }//end setUpBeforeClass() + }//end initializeFile() /** diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php index a224012f2..751b01a8b 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Sniffs; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php new file mode 100644 index 000000000..baba45743 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php @@ -0,0 +1,82 @@ +assertSame('', $seenOutput); + + // Make sure sniffs were registered. + $this->assertGreaterThanOrEqual(1, count($ruleset->sniffCodes)); + + }//end testBuildInStandardsDoNotContainErrors() + + + /** + * Data provider. + * + * @see self::testBuildInStandardsDoNotContainErrors() + * + * @return array> + */ + public static function dataBuildInStandards() + { + // Get a list of all build-in, PHPCS native standards. + $sep = DIRECTORY_SEPARATOR; + $targetDir = dirname(dirname(dirname(__DIR__))).$sep.'src'.$sep.'Standards'.$sep; + $rulesetFiles = glob($targetDir.'*'.$sep.'ruleset.xml'); + + $data = []; + foreach ($rulesetFiles as $file) { + $standardName = basename(dirname($file)); + $data[$standardName] = [ + 'standard' => $standardName, + ]; + } + + return $data; + + }//end dataBuildInStandards() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc deleted file mode 100644 index 5867691c6..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class AnonClassParenthesisOwnerTest extends AbstractMethodUnitTest -{ - - - /** - * Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataAnonClassNoParentheses - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testAnonClassNoParentheses($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); - $this->assertFalse(array_key_exists('parenthesis_owner', $tokens[$anonClass])); - $this->assertFalse(array_key_exists('parenthesis_opener', $tokens[$anonClass])); - $this->assertFalse(array_key_exists('parenthesis_closer', $tokens[$anonClass])); - - }//end testAnonClassNoParentheses() - - - /** - * Test that the next open/close parenthesis after an anonymous class without parenthesis - * do not get assigned the anonymous class as a parenthesis owner. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataAnonClassNoParentheses - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testAnonClassNoParenthesesNextOpenClose($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - $function = $this->getTargetToken($testMarker, T_FUNCTION); - - $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener])); - $this->assertSame($function, $tokens[$opener]['parenthesis_owner']); - - $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer])); - $this->assertSame($function, $tokens[$closer]['parenthesis_owner']); - - }//end testAnonClassNoParenthesesNextOpenClose() - - - /** - * Data provider. - * - * @see testAnonClassNoParentheses() - * @see testAnonClassNoParenthesesNextOpenClose() - * - * @return array - */ - public function dataAnonClassNoParentheses() - { - return [ - ['/* testNoParentheses */'], - ['/* testNoParenthesesAndEmptyTokens */'], - ]; - - }//end dataAnonClassNoParentheses() - - - /** - * Test that anonymous class tokens with parenthesis get assigned a parenthesis owner, - * opener and closer; and that the opener/closer get the anonymous class assigned as owner. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataAnonClassWithParentheses - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testAnonClassWithParentheses($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); - $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); - $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); - - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$anonClass])); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$anonClass])); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$anonClass])); - $this->assertSame($anonClass, $tokens[$anonClass]['parenthesis_owner']); - $this->assertSame($opener, $tokens[$anonClass]['parenthesis_opener']); - $this->assertSame($closer, $tokens[$anonClass]['parenthesis_closer']); - - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener])); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$opener])); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$opener])); - $this->assertSame($anonClass, $tokens[$opener]['parenthesis_owner']); - $this->assertSame($opener, $tokens[$opener]['parenthesis_opener']); - $this->assertSame($closer, $tokens[$opener]['parenthesis_closer']); - - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer])); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$closer])); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$closer])); - $this->assertSame($anonClass, $tokens[$closer]['parenthesis_owner']); - $this->assertSame($opener, $tokens[$closer]['parenthesis_opener']); - $this->assertSame($closer, $tokens[$closer]['parenthesis_closer']); - - }//end testAnonClassWithParentheses() - - - /** - * Data provider. - * - * @see testAnonClassWithParentheses() - * - * @return array - */ - public function dataAnonClassWithParentheses() - { - return [ - ['/* testWithParentheses */'], - ['/* testWithParenthesesAndEmptyTokens */'], - ]; - - }//end dataAnonClassWithParentheses() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc deleted file mode 100644 index ce5c553cf..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc +++ /dev/null @@ -1,35 +0,0 @@ - 10); - -/* testArrayWithComment */ -$var = Array /*comment*/ (1 => 10); - -/* testNestingArray */ -$var = array( - /* testNestedArray */ - array( - 'key' => 'value', - - /* testClosureReturnType */ - 'closure' => function($a) use($global) : Array {}, - ), -); - -/* testFunctionDeclarationParamType */ -function foo(array $a) {} - -/* testFunctionDeclarationReturnType */ -function foo($a) : int|array|null {} - -class Bar { - /* testClassConst */ - const ARRAY = []; - - /* testClassMethod */ - public function array() {} -} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php deleted file mode 100644 index 237258a62..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php +++ /dev/null @@ -1,170 +0,0 @@ - - * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class ArrayKeywordTest extends AbstractMethodUnitTest -{ - - - /** - * Test that the array keyword is correctly tokenized as `T_ARRAY`. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent Optional. The token content to look for. - * - * @dataProvider dataArrayKeyword - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap - * - * @return void - */ - public function testArrayKeyword($testMarker, $testContent='array') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)'); - $this->assertSame('T_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (type)'); - - $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); - $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); - $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); - - }//end testArrayKeyword() - - - /** - * Data provider. - * - * @see testArrayKeyword() - * - * @return array - */ - public function dataArrayKeyword() - { - return [ - 'empty array' => ['/* testEmptyArray */'], - 'array with space before parenthesis' => ['/* testArrayWithSpace */'], - 'array with comment before parenthesis' => [ - '/* testArrayWithComment */', - 'Array', - ], - 'nested: outer array' => ['/* testNestingArray */'], - 'nested: inner array' => ['/* testNestedArray */'], - ]; - - }//end dataArrayKeyword() - - - /** - * Test that the array keyword when used in a type declaration is correctly tokenized as `T_STRING`. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent Optional. The token content to look for. - * - * @dataProvider dataArrayType - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap - * - * @return void - */ - public function testArrayType($testMarker, $testContent='array') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); - $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - - $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); - $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); - $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); - - }//end testArrayType() - - - /** - * Data provider. - * - * @see testArrayType() - * - * @return array - */ - public function dataArrayType() - { - return [ - 'closure return type' => [ - '/* testClosureReturnType */', - 'Array', - ], - 'function param type' => ['/* testFunctionDeclarationParamType */'], - 'function union return type' => ['/* testFunctionDeclarationReturnType */'], - ]; - - }//end dataArrayType() - - - /** - * Verify that the retokenization of `T_ARRAY` tokens to `T_STRING` is handled correctly - * for tokens with the contents 'array' which aren't in actual fact the array keyword. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to look for. - * - * @dataProvider dataNotArrayKeyword - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap - * - * @return void - */ - public function testNotArrayKeyword($testMarker, $testContent='array') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); - $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - - $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); - $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); - $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); - - }//end testNotArrayKeyword() - - - /** - * Data provider. - * - * @see testNotArrayKeyword() - * - * @return array - */ - public function dataNotArrayKeyword() - { - return [ - 'class-constant-name' => [ - '/* testClassConst */', - 'ARRAY', - ], - 'class-method-name' => ['/* testClassMethod */'], - ]; - - }//end dataNotArrayKeyword() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php deleted file mode 100644 index 8ac826f2f..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php +++ /dev/null @@ -1,658 +0,0 @@ - - * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class AttributesTest extends AbstractMethodUnitTest -{ - - - /** - * Test that attributes are parsed correctly. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $length The number of tokens between opener and closer. - * @param array $tokenCodes The codes of tokens inside the attributes. - * - * @dataProvider dataAttribute - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser - * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute - * - * @return void - */ - public function testAttribute($testMarker, $length, $tokenCodes) - { - $tokens = self::$phpcsFile->getTokens(); - - $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); - $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); - - $closer = $tokens[$attribute]['attribute_closer']; - $this->assertSame(($attribute + $length), $closer); - - $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); - - $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); - $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); - - $map = array_map( - function ($token) use ($attribute, $length) { - $this->assertArrayHasKey('attribute_closer', $token); - $this->assertSame(($attribute + $length), $token['attribute_closer']); - - return $token['code']; - }, - array_slice($tokens, ($attribute + 1), ($length - 1)) - ); - - $this->assertSame($tokenCodes, $map); - - }//end testAttribute() - - - /** - * Data provider. - * - * @see testAttribute() - * - * @return array - */ - public function dataAttribute() - { - return [ - [ - '/* testAttribute */', - 2, - [ T_STRING ], - ], - [ - '/* testAttributeWithParams */', - 7, - [ - T_STRING, - T_OPEN_PARENTHESIS, - T_STRING, - T_DOUBLE_COLON, - T_STRING, - T_CLOSE_PARENTHESIS, - ], - ], - [ - '/* testAttributeWithNamedParam */', - 10, - [ - T_STRING, - T_OPEN_PARENTHESIS, - T_PARAM_NAME, - T_COLON, - T_WHITESPACE, - T_STRING, - T_DOUBLE_COLON, - T_STRING, - T_CLOSE_PARENTHESIS, - ], - ], - [ - '/* testAttributeOnFunction */', - 2, - [ T_STRING ], - ], - [ - '/* testAttributeOnFunctionWithParams */', - 17, - [ - T_STRING, - T_OPEN_PARENTHESIS, - T_CONSTANT_ENCAPSED_STRING, - T_COMMA, - T_WHITESPACE, - T_PARAM_NAME, - T_COLON, - T_WHITESPACE, - T_OPEN_SHORT_ARRAY, - T_CONSTANT_ENCAPSED_STRING, - T_WHITESPACE, - T_DOUBLE_ARROW, - T_WHITESPACE, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_SHORT_ARRAY, - T_CLOSE_PARENTHESIS, - ], - ], - [ - '/* testAttributeWithShortClosureParameter */', - 17, - [ - T_STRING, - T_OPEN_PARENTHESIS, - T_STATIC, - T_WHITESPACE, - T_FN, - T_WHITESPACE, - T_OPEN_PARENTHESIS, - T_VARIABLE, - T_CLOSE_PARENTHESIS, - T_WHITESPACE, - T_FN_ARROW, - T_WHITESPACE, - T_BOOLEAN_NOT, - T_WHITESPACE, - T_VARIABLE, - T_CLOSE_PARENTHESIS, - ], - ], - [ - '/* testAttributeGrouping */', - 26, - [ - T_STRING, - T_COMMA, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_PARENTHESIS, - T_COMMA, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_CONSTANT_ENCAPSED_STRING, - T_COMMA, - T_WHITESPACE, - T_PARAM_NAME, - T_COLON, - T_WHITESPACE, - T_OPEN_SHORT_ARRAY, - T_CONSTANT_ENCAPSED_STRING, - T_WHITESPACE, - T_DOUBLE_ARROW, - T_WHITESPACE, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_SHORT_ARRAY, - T_CLOSE_PARENTHESIS, - ], - ], - [ - '/* testAttributeMultiline */', - 31, - [ - T_WHITESPACE, - T_WHITESPACE, - T_STRING, - T_COMMA, - T_WHITESPACE, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_PARENTHESIS, - T_COMMA, - T_WHITESPACE, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_CONSTANT_ENCAPSED_STRING, - T_COMMA, - T_WHITESPACE, - T_PARAM_NAME, - T_COLON, - T_WHITESPACE, - T_OPEN_SHORT_ARRAY, - T_CONSTANT_ENCAPSED_STRING, - T_WHITESPACE, - T_DOUBLE_ARROW, - T_WHITESPACE, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_SHORT_ARRAY, - T_CLOSE_PARENTHESIS, - T_WHITESPACE, - ], - ], - [ - '/* testFqcnAttribute */', - 13, - [ - T_STRING, - T_NS_SEPARATOR, - T_STRING, - T_COMMA, - T_WHITESPACE, - T_NS_SEPARATOR, - T_STRING, - T_NS_SEPARATOR, - T_STRING, - T_OPEN_PARENTHESIS, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_PARENTHESIS, - ], - ], - ]; - - }//end dataAttribute() - - - /** - * Test that multiple attributes on the same line are parsed correctly. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser - * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute - * - * @return void - */ - public function testTwoAttributesOnTheSameLine() - { - $tokens = self::$phpcsFile->getTokens(); - - $attribute = $this->getTargetToken('/* testTwoAttributeOnTheSameLine */', T_ATTRIBUTE); - $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); - - $closer = $tokens[$attribute]['attribute_closer']; - $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); - $this->assertSame(T_ATTRIBUTE, $tokens[($closer + 2)]['code']); - $this->assertArrayHasKey('attribute_closer', $tokens[($closer + 2)]); - - }//end testTwoAttributesOnTheSameLine() - - - /** - * Test that attribute followed by a line comment is parsed correctly. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser - * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute - * - * @return void - */ - public function testAttributeAndLineComment() - { - $tokens = self::$phpcsFile->getTokens(); - - $attribute = $this->getTargetToken('/* testAttributeAndCommentOnTheSameLine */', T_ATTRIBUTE); - $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); - - $closer = $tokens[$attribute]['attribute_closer']; - $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); - $this->assertSame(T_COMMENT, $tokens[($closer + 2)]['code']); - - }//end testAttributeAndLineComment() - - - /** - * Test that attributes on function declaration parameters are parsed correctly. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $position The token position (starting from T_FUNCTION) of T_ATTRIBUTE token. - * @param int $length The number of tokens between opener and closer. - * @param array $tokenCodes The codes of tokens inside the attributes. - * - * @dataProvider dataAttributeOnParameters - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser - * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute - * - * @return void - */ - public function testAttributeOnParameters($testMarker, $position, $length, array $tokenCodes) - { - $tokens = self::$phpcsFile->getTokens(); - - $function = $this->getTargetToken($testMarker, T_FUNCTION); - $attribute = ($function + $position); - - $this->assertSame(T_ATTRIBUTE, $tokens[$attribute]['code']); - $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); - - $this->assertSame(($attribute + $length), $tokens[$attribute]['attribute_closer']); - - $closer = $tokens[$attribute]['attribute_closer']; - $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); - $this->assertSame(T_STRING, $tokens[($closer + 2)]['code']); - $this->assertSame('int', $tokens[($closer + 2)]['content']); - - $this->assertSame(T_VARIABLE, $tokens[($closer + 4)]['code']); - $this->assertSame('$param', $tokens[($closer + 4)]['content']); - - $map = array_map( - function ($token) use ($attribute, $length) { - $this->assertArrayHasKey('attribute_closer', $token); - $this->assertSame(($attribute + $length), $token['attribute_closer']); - - return $token['code']; - }, - array_slice($tokens, ($attribute + 1), ($length - 1)) - ); - - $this->assertSame($tokenCodes, $map); - - }//end testAttributeOnParameters() - - - /** - * Data provider. - * - * @see testAttributeOnParameters() - * - * @return array - */ - public function dataAttributeOnParameters() - { - return [ - [ - '/* testSingleAttributeOnParameter */', - 4, - 2, - [T_STRING], - ], - [ - '/* testMultipleAttributesOnParameter */', - 4, - 10, - [ - T_STRING, - T_COMMA, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_COMMENT, - T_WHITESPACE, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_PARENTHESIS, - ], - ], - [ - '/* testMultilineAttributesOnParameter */', - 4, - 13, - [ - T_WHITESPACE, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_WHITESPACE, - T_WHITESPACE, - T_CONSTANT_ENCAPSED_STRING, - T_WHITESPACE, - T_WHITESPACE, - T_CLOSE_PARENTHESIS, - T_WHITESPACE, - T_WHITESPACE, - ], - ], - ]; - - }//end dataAttributeOnParameters() - - - /** - * Test that an attribute containing text which looks like a PHP close tag is tokenized correctly. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $length The number of tokens between opener and closer. - * @param array $expectedTokensAttribute The codes of tokens inside the attributes. - * @param array $expectedTokensAfter The codes of tokens after the attributes. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute - * - * @dataProvider dataAttributeOnTextLookingLikeCloseTag - * - * @return void - */ - public function testAttributeContainingTextLookingLikeCloseTag($testMarker, $length, array $expectedTokensAttribute, array $expectedTokensAfter) - { - $tokens = self::$phpcsFile->getTokens(); - - $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); - - $this->assertSame('T_ATTRIBUTE', $tokens[$attribute]['type']); - $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); - - $closer = $tokens[$attribute]['attribute_closer']; - $this->assertSame(($attribute + $length), $closer); - $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); - $this->assertSame('T_ATTRIBUTE_END', $tokens[$closer]['type']); - - $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); - $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); - - $i = ($attribute + 1); - foreach ($expectedTokensAttribute as $item) { - list($expectedType, $expectedContents) = $item; - $this->assertSame($expectedType, $tokens[$i]['type']); - $this->assertSame($expectedContents, $tokens[$i]['content']); - $this->assertArrayHasKey('attribute_opener', $tokens[$i]); - $this->assertArrayHasKey('attribute_closer', $tokens[$i]); - ++$i; - } - - $i = ($closer + 1); - foreach ($expectedTokensAfter as $expectedCode) { - $this->assertSame($expectedCode, $tokens[$i]['code']); - ++$i; - } - - }//end testAttributeContainingTextLookingLikeCloseTag() - - - /** - * Data provider. - * - * @see dataAttributeOnTextLookingLikeCloseTag() - * - * @return array - */ - public function dataAttributeOnTextLookingLikeCloseTag() - { - return [ - [ - '/* testAttributeContainingTextLookingLikeCloseTag */', - 5, - [ - [ - 'T_STRING', - 'DeprecationReason', - ], - [ - 'T_OPEN_PARENTHESIS', - '(', - ], - [ - 'T_CONSTANT_ENCAPSED_STRING', - "'reason: '", - ], - [ - 'T_CLOSE_PARENTHESIS', - ')', - ], - [ - 'T_ATTRIBUTE_END', - ']', - ], - ], - [ - T_WHITESPACE, - T_FUNCTION, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_CLOSE_PARENTHESIS, - T_WHITESPACE, - T_OPEN_CURLY_BRACKET, - T_CLOSE_CURLY_BRACKET, - ], - ], - [ - '/* testAttributeContainingMultilineTextLookingLikeCloseTag */', - 8, - [ - [ - 'T_STRING', - 'DeprecationReason', - ], - [ - 'T_OPEN_PARENTHESIS', - '(', - ], - [ - 'T_WHITESPACE', - "\n", - ], - [ - 'T_WHITESPACE', - " ", - ], - [ - 'T_CONSTANT_ENCAPSED_STRING', - "'reason: '", - ], - [ - 'T_WHITESPACE', - "\n", - ], - [ - 'T_CLOSE_PARENTHESIS', - ')', - ], - [ - 'T_ATTRIBUTE_END', - ']', - ], - ], - [ - T_WHITESPACE, - T_FUNCTION, - T_WHITESPACE, - T_STRING, - T_OPEN_PARENTHESIS, - T_CLOSE_PARENTHESIS, - T_WHITESPACE, - T_OPEN_CURLY_BRACKET, - T_CLOSE_CURLY_BRACKET, - ], - ], - ]; - - }//end dataAttributeOnTextLookingLikeCloseTag() - - - /** - * Test that invalid attribute (or comment starting with #[ and without ]) are parsed correctly. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser - * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute - * - * @return void - */ - public function testInvalidAttribute() - { - $tokens = self::$phpcsFile->getTokens(); - - $attribute = $this->getTargetToken('/* testInvalidAttribute */', T_ATTRIBUTE); - - $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); - $this->assertNull($tokens[$attribute]['attribute_closer']); - - }//end testInvalidAttribute() - - - /** - * Test that nested attributes are parsed correctly. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser - * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute - * - * @return void - */ - public function testNestedAttributes() - { - $tokens = self::$phpcsFile->getTokens(); - $tokenCodes = [ - T_STRING, - T_NS_SEPARATOR, - T_STRING, - T_OPEN_PARENTHESIS, - T_FN, - T_WHITESPACE, - T_OPEN_PARENTHESIS, - T_ATTRIBUTE, - T_STRING, - T_OPEN_PARENTHESIS, - T_CONSTANT_ENCAPSED_STRING, - T_CLOSE_PARENTHESIS, - T_ATTRIBUTE_END, - T_WHITESPACE, - T_VARIABLE, - T_CLOSE_PARENTHESIS, - T_WHITESPACE, - T_FN_ARROW, - T_WHITESPACE, - T_STRING_CAST, - T_WHITESPACE, - T_VARIABLE, - T_CLOSE_PARENTHESIS, - ]; - - $attribute = $this->getTargetToken('/* testNestedAttributes */', T_ATTRIBUTE); - $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); - - $closer = $tokens[$attribute]['attribute_closer']; - $this->assertSame(($attribute + 24), $closer); - - $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); - - $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); - $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); - - $this->assertArrayNotHasKey('nested_attributes', $tokens[$attribute]); - $this->assertArrayHasKey('nested_attributes', $tokens[($attribute + 8)]); - $this->assertSame([$attribute => ($attribute + 24)], $tokens[($attribute + 8)]['nested_attributes']); - - $test = function (array $tokens, $length, $nestedMap) use ($attribute) { - foreach ($tokens as $token) { - $this->assertArrayHasKey('attribute_closer', $token); - $this->assertSame(($attribute + $length), $token['attribute_closer']); - $this->assertSame($nestedMap, $token['nested_attributes']); - } - }; - - $test(array_slice($tokens, ($attribute + 1), 7), 24, [$attribute => $attribute + 24]); - $test(array_slice($tokens, ($attribute + 8), 1), 8 + 5, [$attribute => $attribute + 24]); - - // Length here is 8 (nested attribute offset) + 5 (real length). - $test( - array_slice($tokens, ($attribute + 9), 4), - 8 + 5, - [ - $attribute => $attribute + 24, - $attribute + 8 => $attribute + 13, - ] - ); - - $test(array_slice($tokens, ($attribute + 13), 1), 8 + 5, [$attribute => $attribute + 24]); - $test(array_slice($tokens, ($attribute + 14), 10), 24, [$attribute => $attribute + 24]); - - $map = array_map( - static function ($token) { - return $token['code']; - }, - array_slice($tokens, ($attribute + 1), 23) - ); - - $this->assertSame($tokenCodes, $map); - - }//end testNestedAttributes() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php deleted file mode 100644 index 33cff3a2c..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php +++ /dev/null @@ -1,229 +0,0 @@ - - * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillEnumTest extends AbstractMethodUnitTest -{ - - - /** - * Test that the "enum" keyword is tokenized as such. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $testContent The token content to look for. - * @param int $openerOffset Offset to find expected scope opener. - * @param int $closerOffset Offset to find expected scope closer. - * - * @dataProvider dataEnums - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testEnums($testMarker, $testContent, $openerOffset, $closerOffset) - { - $tokens = self::$phpcsFile->getTokens(); - - $enum = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); - - $this->assertSame(T_ENUM, $tokens[$enum]['code']); - $this->assertSame('T_ENUM', $tokens[$enum]['type']); - - $this->assertArrayHasKey('scope_condition', $tokens[$enum]); - $this->assertArrayHasKey('scope_opener', $tokens[$enum]); - $this->assertArrayHasKey('scope_closer', $tokens[$enum]); - - $this->assertSame($enum, $tokens[$enum]['scope_condition']); - - $scopeOpener = $tokens[$enum]['scope_opener']; - $scopeCloser = $tokens[$enum]['scope_closer']; - - $expectedScopeOpener = ($enum + $openerOffset); - $expectedScopeCloser = ($enum + $closerOffset); - - $this->assertSame($expectedScopeOpener, $scopeOpener); - $this->assertArrayHasKey('scope_condition', $tokens[$scopeOpener]); - $this->assertArrayHasKey('scope_opener', $tokens[$scopeOpener]); - $this->assertArrayHasKey('scope_closer', $tokens[$scopeOpener]); - $this->assertSame($enum, $tokens[$scopeOpener]['scope_condition']); - $this->assertSame($scopeOpener, $tokens[$scopeOpener]['scope_opener']); - $this->assertSame($scopeCloser, $tokens[$scopeOpener]['scope_closer']); - - $this->assertSame($expectedScopeCloser, $scopeCloser); - $this->assertArrayHasKey('scope_condition', $tokens[$scopeCloser]); - $this->assertArrayHasKey('scope_opener', $tokens[$scopeCloser]); - $this->assertArrayHasKey('scope_closer', $tokens[$scopeCloser]); - $this->assertSame($enum, $tokens[$scopeCloser]['scope_condition']); - $this->assertSame($scopeOpener, $tokens[$scopeCloser]['scope_opener']); - $this->assertSame($scopeCloser, $tokens[$scopeCloser]['scope_closer']); - - }//end testEnums() - - - /** - * Data provider. - * - * @see testEnums() - * - * @return array - */ - public function dataEnums() - { - return [ - [ - '/* testPureEnum */', - 'enum', - 4, - 12, - ], - [ - '/* testBackedIntEnum */', - 'enum', - 7, - 29, - ], - [ - '/* testBackedStringEnum */', - 'enum', - 8, - 30, - ], - [ - '/* testComplexEnum */', - 'enum', - 11, - 72, - ], - [ - '/* testEnumWithEnumAsClassName */', - 'enum', - 6, - 7, - ], - [ - '/* testEnumIsCaseInsensitive */', - 'EnUm', - 4, - 5, - ], - [ - '/* testDeclarationContainingComment */', - 'enum', - 6, - 14, - ], - ]; - - }//end dataEnums() - - - /** - * Test that "enum" when not used as the keyword is still tokenized as `T_STRING`. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $testContent The token content to look for. - * - * @dataProvider dataNotEnums - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testNotEnums($testMarker, $testContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); - - }//end testNotEnums() - - - /** - * Data provider. - * - * @see testNotEnums() - * - * @return array - */ - public function dataNotEnums() - { - return [ - [ - '/* testEnumAsClassNameAfterEnumKeyword */', - 'Enum', - ], - [ - '/* testEnumUsedAsClassName */', - 'Enum', - ], - [ - '/* testEnumUsedAsClassConstantName */', - 'ENUM', - ], - [ - '/* testEnumUsedAsMethodName */', - 'enum', - ], - [ - '/* testEnumUsedAsPropertyName */', - 'enum', - ], - [ - '/* testEnumUsedAsFunctionName */', - 'enum', - ], - [ - '/* testEnumUsedAsEnumName */', - 'Enum', - ], - [ - '/* testEnumUsedAsNamespaceName */', - 'Enum', - ], - [ - '/* testEnumUsedAsPartOfNamespaceName */', - 'Enum', - ], - [ - '/* testEnumUsedInObjectInitialization */', - 'Enum', - ], - [ - '/* testEnumAsFunctionCall */', - 'enum', - ], - [ - '/* testEnumAsFunctionCallWithNamespace */', - 'enum', - ], - [ - '/* testClassConstantFetchWithEnumAsClassName */', - 'Enum', - ], - [ - '/* testClassConstantFetchWithEnumAsConstantName */', - 'ENUM', - ], - [ - '/* testParseErrorMissingName */', - 'enum', - ], - [ - '/* testParseErrorLiveCoding */', - 'enum', - ], - ]; - - }//end dataNotEnums() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php deleted file mode 100644 index e1c55bd93..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillExplicitOctalNotationTest extends AbstractMethodUnitTest -{ - - - /** - * Test that explicitly-defined octal values are tokenized as a single number and not as a number and a string. - * - * @param string $marker The comment which prefaces the target token in the test file. - * @param string $value The expected content of the token - * @param int|string $nextToken The expected next token. - * @param string $nextContent The expected content of the next token. - * - * @dataProvider dataExplicitOctalNotation - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testExplicitOctalNotation($marker, $value, $nextToken, $nextContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $number = $this->getTargetToken($marker, [T_LNUMBER]); - - $this->assertSame($value, $tokens[$number]['content'], 'Content of integer token does not match expectation'); - - $this->assertSame($nextToken, $tokens[($number + 1)]['code'], 'Next token is not the expected type, but '.$tokens[($number + 1)]['type']); - $this->assertSame($nextContent, $tokens[($number + 1)]['content'], 'Next token did not have the expected contents'); - - }//end testExplicitOctalNotation() - - - /** - * Data provider. - * - * @see testExplicitOctalNotation() - * - * @return array - */ - public function dataExplicitOctalNotation() - { - return [ - [ - 'marker' => '/* testExplicitOctal */', - 'value' => '0o137041', - 'nextToken' => T_SEMICOLON, - 'nextContent' => ';', - ], - [ - 'marker' => '/* testExplicitOctalCapitalised */', - 'value' => '0O137041', - 'nextToken' => T_SEMICOLON, - 'nextContent' => ';', - ], - [ - 'marker' => '/* testExplicitOctalWithNumericSeparator */', - 'value' => '0o137_041', - 'nextToken' => T_SEMICOLON, - 'nextContent' => ';', - ], - [ - 'marker' => '/* testInvalid1 */', - 'value' => '0', - 'nextToken' => T_STRING, - 'nextContent' => 'o_137', - ], - [ - 'marker' => '/* testInvalid2 */', - 'value' => '0', - 'nextToken' => T_STRING, - 'nextContent' => 'O_41', - ], - [ - 'marker' => '/* testInvalid3 */', - 'value' => '0', - 'nextToken' => T_STRING, - 'nextContent' => 'o91', - ], - [ - 'marker' => '/* testInvalid4 */', - 'value' => '0O2', - 'nextToken' => T_LNUMBER, - 'nextContent' => '82', - ], - [ - 'marker' => '/* testInvalid5 */', - 'value' => '0o2', - 'nextToken' => T_LNUMBER, - 'nextContent' => '8_2', - ], - [ - 'marker' => '/* testInvalid6 */', - 'value' => '0o2', - 'nextToken' => T_STRING, - 'nextContent' => '_82', - ], - ]; - - }//end dataExplicitOctalNotation() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php deleted file mode 100644 index 4d0f4c064..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php +++ /dev/null @@ -1,802 +0,0 @@ - - * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillFnTokenTest extends AbstractMethodUnitTest -{ - - - /** - * Test simple arrow functions. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testSimple() - { - foreach (['/* testStandard */', '/* testMixedCase */'] as $comment) { - $token = $this->getTargetToken($comment, T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 12); - } - - }//end testSimple() - - - /** - * Test whitespace inside arrow function definitions. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testWhitespace() - { - $token = $this->getTargetToken('/* testWhitespace */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 6, 13); - - }//end testWhitespace() - - - /** - * Test comments inside arrow function definitions. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testComment() - { - $token = $this->getTargetToken('/* testComment */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 8, 15); - - }//end testComment() - - - /** - * Test heredocs inside arrow function definitions. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testHeredoc() - { - $token = $this->getTargetToken('/* testHeredoc */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 4, 9); - - }//end testHeredoc() - - - /** - * Test nested arrow functions. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNestedOuter() - { - $token = $this->getTargetToken('/* testNestedOuter */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 25); - - }//end testNestedOuter() - - - /** - * Test nested arrow functions. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNestedInner() - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken('/* testNestedInner */', T_FN); - $this->backfillHelper($token, true); - - $expectedScopeOpener = ($token + 5); - $expectedScopeCloser = ($token + 16); - - $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the semicolon token'); - - $opener = $tokens[$token]['scope_opener']; - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the semicolon token'); - - $closer = $tokens[$token]['scope_closer']; - $this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token of the "outer" arrow function (shared scope closer)'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the semicolon token'); - - }//end testNestedInner() - - - /** - * Test nested arrow functions with a shared closer. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNestedSharedCloser() - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken('/* testNestedSharedCloserOuter */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 4, 20); - - $token = $this->getTargetToken('/* testNestedSharedCloserInner */', T_FN); - $this->backfillHelper($token, true); - - $expectedScopeOpener = ($token + 4); - $expectedScopeCloser = ($token + 12); - - $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for "inner" arrow function is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for "inner" arrow function is not the TRUE token'); - - $opener = $tokens[$token]['scope_opener']; - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for "inner" arrow function is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for "inner" arrow function is not the semicolon token'); - - $closer = $tokens[$token]['scope_closer']; - $this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener for "inner" arrow function is not the arrow token of the "outer" arrow function (shared scope closer)'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for "inner" arrow function is not the TRUE token'); - - }//end testNestedSharedCloser() - - - /** - * Test arrow functions that call functions. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testFunctionCall() - { - $token = $this->getTargetToken('/* testFunctionCall */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 17); - - }//end testFunctionCall() - - - /** - * Test arrow functions that are included in chained calls. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testChainedFunctionCall() - { - $token = $this->getTargetToken('/* testChainedFunctionCall */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 12, 'bracket'); - - }//end testChainedFunctionCall() - - - /** - * Test arrow functions that are used as function arguments. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testFunctionArgument() - { - $token = $this->getTargetToken('/* testFunctionArgument */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 8, 15, 'comma'); - - }//end testFunctionArgument() - - - /** - * Test arrow functions that use closures. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testClosure() - { - $token = $this->getTargetToken('/* testClosure */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 60, 'comma'); - - }//end testClosure() - - - /** - * Test arrow functions using an array index. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testArrayIndex() - { - $token = $this->getTargetToken('/* testArrayIndex */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 8, 17, 'comma'); - - }//end testArrayIndex() - - - /** - * Test arrow functions with a return type. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testReturnType() - { - $token = $this->getTargetToken('/* testReturnType */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 11, 18, 'comma'); - - }//end testReturnType() - - - /** - * Test arrow functions that return a reference. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testReference() - { - $token = $this->getTargetToken('/* testReference */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 6, 9); - - }//end testReference() - - - /** - * Test arrow functions that are grouped by parenthesis. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testGrouped() - { - $token = $this->getTargetToken('/* testGrouped */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 8); - - }//end testGrouped() - - - /** - * Test arrow functions that are used as array values. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testArrayValue() - { - $token = $this->getTargetToken('/* testArrayValue */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 4, 9, 'comma'); - - }//end testArrayValue() - - - /** - * Test arrow functions that are used as array values with no trailing comma. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testArrayValueNoTrailingComma() - { - $token = $this->getTargetToken('/* testArrayValueNoTrailingComma */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 4, 8, 'closing parenthesis'); - - }//end testArrayValueNoTrailingComma() - - - /** - * Test arrow functions that use the yield keyword. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testYield() - { - $token = $this->getTargetToken('/* testYield */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 14); - - }//end testYield() - - - /** - * Test arrow functions that use nullable namespace types. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNullableNamespace() - { - $token = $this->getTargetToken('/* testNullableNamespace */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 15, 18); - - }//end testNullableNamespace() - - - /** - * Test arrow functions that use the namespace operator in the return type. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNamespaceOperatorInTypes() - { - $token = $this->getTargetToken('/* testNamespaceOperatorInTypes */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 16, 19); - - }//end testNamespaceOperatorInTypes() - - - /** - * Test arrow functions that use self/parent/callable/array/static return types. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testKeywordReturnTypes() - { - $tokens = self::$phpcsFile->getTokens(); - - $testMarkers = [ - 'Self', - 'Parent', - 'Callable', - 'Array', - 'Static', - ]; - - foreach ($testMarkers as $marker) { - $token = $this->getTargetToken('/* test'.$marker.'ReturnType */', T_FN); - $this->backfillHelper($token); - - $expectedScopeOpener = ($token + 11); - $expectedScopeCloser = ($token + 14); - - $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], "Scope opener is not the arrow token (for $marker)"); - $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], "Scope closer is not the semicolon token(for $marker)"); - - $opener = $tokens[$token]['scope_opener']; - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], "Opener scope opener is not the arrow token(for $marker)"); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], "Opener scope closer is not the semicolon token(for $marker)"); - - $closer = $tokens[$token]['scope_closer']; - $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], "Closer scope opener is not the arrow token(for $marker)"); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], "Closer scope closer is not the semicolon token(for $marker)"); - } - - }//end testKeywordReturnTypes() - - - /** - * Test arrow function with a union parameter type. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testUnionParamType() - { - $token = $this->getTargetToken('/* testUnionParamType */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 13, 21); - - }//end testUnionParamType() - - - /** - * Test arrow function with a union return type. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testUnionReturnType() - { - $token = $this->getTargetToken('/* testUnionReturnType */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 11, 18); - - }//end testUnionReturnType() - - - /** - * Test arrow functions used in ternary operators. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testTernary() - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken('/* testTernary */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 40); - - $token = $this->getTargetToken('/* testTernaryThen */', T_FN); - $this->backfillHelper($token); - - $expectedScopeOpener = ($token + 8); - $expectedScopeCloser = ($token + 12); - - $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for THEN is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for THEN is not the semicolon token'); - - $opener = $tokens[$token]['scope_opener']; - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for THEN is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for THEN is not the semicolon token'); - - $closer = $tokens[$token]['scope_closer']; - $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener for THEN is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for THEN is not the semicolon token'); - - $token = $this->getTargetToken('/* testTernaryElse */', T_FN); - $this->backfillHelper($token, true); - - $expectedScopeOpener = ($token + 8); - $expectedScopeCloser = ($token + 11); - - $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for ELSE is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for ELSE is not the semicolon token'); - - $opener = $tokens[$token]['scope_opener']; - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for ELSE is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for ELSE is not the semicolon token'); - - $closer = $tokens[$token]['scope_closer']; - $this->assertSame(($token - 24), $tokens[$closer]['scope_opener'], 'Closer scope opener for ELSE is not the arrow token of the "outer" arrow function (shared scope closer)'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for ELSE is not the semicolon token'); - - }//end testTernary() - - - /** - * Test typed arrow functions used in ternary operators. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testTernaryWithTypes() - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken('/* testTernaryWithTypes */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 15, 27); - - }//end testTernaryWithTypes() - - - /** - * Test arrow function returning a match control structure. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testWithMatchValue() - { - $token = $this->getTargetToken('/* testWithMatchValue */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 44); - - }//end testWithMatchValue() - - - /** - * Test arrow function returning a match control structure with something behind it. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testWithMatchValueAndMore() - { - $token = $this->getTargetToken('/* testWithMatchValueAndMore */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 48); - - }//end testWithMatchValueAndMore() - - - /** - * Test match control structure returning arrow functions. - * - * @param string $testMarker The comment prefacing the target token. - * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. - * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. - * @param string $expectedCloserType The type of token expected for the scope closer. - * @param string $expectedCloserFriendlyName A friendly name for the type of token expected for the scope closer - * to be used in the error message for failing tests. - * - * @dataProvider dataInMatchValue - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testInMatchValue($testMarker, $openerOffset, $closerOffset, $expectedCloserType, $expectedCloserFriendlyName) - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserFriendlyName); - - $this->assertSame($expectedCloserType, $tokens[($token + $closerOffset)]['type'], 'Mismatched scope closer type'); - - }//end testInMatchValue() - - - /** - * Data provider. - * - * @see testInMatchValue() - * - * @return array - */ - public function dataInMatchValue() - { - return [ - 'not_last_value' => [ - '/* testInMatchNotLastValue */', - 5, - 11, - 'T_COMMA', - 'comma', - ], - 'last_value_with_trailing_comma' => [ - '/* testInMatchLastValueWithTrailingComma */', - 5, - 11, - 'T_COMMA', - 'comma', - ], - 'last_value_without_trailing_comma_1' => [ - '/* testInMatchLastValueNoTrailingComma1 */', - 5, - 10, - 'T_CLOSE_PARENTHESIS', - 'close parenthesis', - ], - 'last_value_without_trailing_comma_2' => [ - '/* testInMatchLastValueNoTrailingComma2 */', - 5, - 11, - 'T_VARIABLE', - '$y variable', - ], - ]; - - }//end dataInMatchValue() - - - /** - * Test arrow function nested within a method declaration. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNestedInMethod() - { - $token = $this->getTargetToken('/* testNestedInMethod */', T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 17); - - }//end testNestedInMethod() - - - /** - * Verify that "fn" keywords which are not arrow functions get tokenized as T_STRING and don't - * have the extra token array indexes. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to look for. - * - * @dataProvider dataNotAnArrowFunction - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNotAnArrowFunction($testMarker, $testContent='fn') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_STRING, T_FN], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING'); - - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); - $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); - $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); - - }//end testNotAnArrowFunction() - - - /** - * Data provider. - * - * @see testNotAnArrowFunction() - * - * @return array - */ - public function dataNotAnArrowFunction() - { - return [ - ['/* testFunctionName */'], - [ - '/* testConstantDeclaration */', - 'FN', - ], - [ - '/* testConstantDeclarationLower */', - 'fn', - ], - ['/* testStaticMethodName */'], - ['/* testPropertyAssignment */'], - [ - '/* testAnonClassMethodName */', - 'fN', - ], - ['/* testNonArrowStaticMethodCall */'], - [ - '/* testNonArrowConstantAccess */', - 'FN', - ], - [ - '/* testNonArrowConstantAccessMixed */', - 'Fn', - ], - ['/* testNonArrowObjectMethodCall */'], - [ - '/* testNonArrowObjectMethodCallUpper */', - 'FN', - ], - [ - '/* testNonArrowNamespacedFunctionCall */', - 'Fn', - ], - ['/* testNonArrowNamespaceOperatorFunctionCall */'], - ['/* testNonArrowFunctionNameWithUnionTypes */'], - ['/* testLiveCoding */'], - ]; - - }//end dataNotAnArrowFunction() - - - /** - * Helper function to check that all token keys are correctly set for T_FN tokens. - * - * @param int $token The T_FN token to check. - * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. - * This should be set to "true" when testing nested arrow functions, - * where the "inner" arrow function shares a scope closer with the - * "outer" arrow function, as the 'scope_condition' for the scope closer - * of the "inner" arrow function will point to the "outer" arrow function. - * - * @return void - */ - private function backfillHelper($token, $skipScopeCloserCheck=false) - { - $tokens = self::$phpcsFile->getTokens(); - - $this->assertTrue(array_key_exists('scope_condition', $tokens[$token]), 'Scope condition is not set'); - $this->assertTrue(array_key_exists('scope_opener', $tokens[$token]), 'Scope opener is not set'); - $this->assertTrue(array_key_exists('scope_closer', $tokens[$token]), 'Scope closer is not set'); - $this->assertSame($tokens[$token]['scope_condition'], $token, 'Scope condition is not the T_FN token'); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$token]), 'Parenthesis owner is not set'); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$token]), 'Parenthesis opener is not set'); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$token]), 'Parenthesis closer is not set'); - $this->assertSame($tokens[$token]['parenthesis_owner'], $token, 'Parenthesis owner is not the T_FN token'); - - $opener = $tokens[$token]['scope_opener']; - $this->assertTrue(array_key_exists('scope_condition', $tokens[$opener]), 'Opener scope condition is not set'); - $this->assertTrue(array_key_exists('scope_opener', $tokens[$opener]), 'Opener scope opener is not set'); - $this->assertTrue(array_key_exists('scope_closer', $tokens[$opener]), 'Opener scope closer is not set'); - $this->assertSame($tokens[$opener]['scope_condition'], $token, 'Opener scope condition is not the T_FN token'); - $this->assertSame(T_FN_ARROW, $tokens[$opener]['code'], 'Arrow scope opener not tokenized as T_FN_ARROW (code)'); - $this->assertSame('T_FN_ARROW', $tokens[$opener]['type'], 'Arrow scope opener not tokenized as T_FN_ARROW (type)'); - - $closer = $tokens[$token]['scope_closer']; - $this->assertTrue(array_key_exists('scope_condition', $tokens[$closer]), 'Closer scope condition is not set'); - $this->assertTrue(array_key_exists('scope_opener', $tokens[$closer]), 'Closer scope opener is not set'); - $this->assertTrue(array_key_exists('scope_closer', $tokens[$closer]), 'Closer scope closer is not set'); - if ($skipScopeCloserCheck === false) { - $this->assertSame($tokens[$closer]['scope_condition'], $token, 'Closer scope condition is not the T_FN token'); - } - - $opener = $tokens[$token]['parenthesis_opener']; - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]), 'Opening parenthesis owner is not set'); - $this->assertSame($tokens[$opener]['parenthesis_owner'], $token, 'Opening parenthesis owner is not the T_FN token'); - - $closer = $tokens[$token]['parenthesis_closer']; - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]), 'Closing parenthesis owner is not set'); - $this->assertSame($tokens[$closer]['parenthesis_owner'], $token, 'Closing parenthesis owner is not the T_FN token'); - - }//end backfillHelper() - - - /** - * Helper function to check that the scope opener/closer positions are correctly set for T_FN tokens. - * - * @param int $token The T_FN token to check. - * @param int $openerOffset The expected offset of the scope opener in relation to - * the fn keyword. - * @param int $closerOffset The expected offset of the scope closer in relation to - * the fn keyword. - * @param string $expectedCloserType Optional. The type of token expected for the scope closer. - * - * @return void - */ - private function scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserType='semicolon') - { - $tokens = self::$phpcsFile->getTokens(); - $expectedScopeOpener = ($token + $openerOffset); - $expectedScopeCloser = ($token + $closerOffset); - - $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the '.$expectedCloserType.' token'); - - $opener = $tokens[$token]['scope_opener']; - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the '.$expectedCloserType.' token'); - - $closer = $tokens[$token]['scope_closer']; - $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the '.$expectedCloserType.' token'); - - }//end scopePositionTestHelper() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php deleted file mode 100644 index 80f909acd..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php +++ /dev/null @@ -1,529 +0,0 @@ - - * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -use PHP_CodeSniffer\Util\Tokens; - -class BackfillMatchTokenTest extends AbstractMethodUnitTest -{ - - - /** - * Test tokenization of match expressions. - * - * @param string $testMarker The comment prefacing the target token. - * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. - * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. - * @param string $testContent The token content to look for. - * - * @dataProvider dataMatchExpression - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testMatchExpression($testMarker, $openerOffset, $closerOffset, $testContent='match') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame(T_MATCH, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (code)'); - $this->assertSame('T_MATCH', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (type)'); - - $this->scopeTestHelper($token, $openerOffset, $closerOffset); - $this->parenthesisTestHelper($token); - - }//end testMatchExpression() - - - /** - * Data provider. - * - * @see testMatchExpression() - * - * @return array - */ - public function dataMatchExpression() - { - return [ - 'simple_match' => [ - '/* testMatchSimple */', - 6, - 33, - ], - 'no_trailing_comma' => [ - '/* testMatchNoTrailingComma */', - 6, - 24, - ], - 'with_default_case' => [ - '/* testMatchWithDefault */', - 6, - 33, - ], - 'expression_in_condition' => [ - '/* testMatchExpressionInCondition */', - 6, - 77, - ], - 'multicase' => [ - '/* testMatchMultiCase */', - 6, - 40, - ], - 'multicase_trailing_comma_in_case' => [ - '/* testMatchMultiCaseTrailingCommaInCase */', - 6, - 47, - ], - 'in_closure_not_lowercase' => [ - '/* testMatchInClosureNotLowercase */', - 6, - 36, - 'Match', - ], - 'in_arrow_function' => [ - '/* testMatchInArrowFunction */', - 5, - 36, - ], - 'arrow_function_in_match_no_trailing_comma' => [ - '/* testArrowFunctionInMatchNoTrailingComma */', - 6, - 44, - ], - 'in_function_call_param_not_lowercase' => [ - '/* testMatchInFunctionCallParamNotLowercase */', - 8, - 32, - 'MATCH', - ], - 'in_method_call_param' => [ - '/* testMatchInMethodCallParam */', - 5, - 13, - ], - 'discard_result' => [ - '/* testMatchDiscardResult */', - 6, - 18, - ], - 'duplicate_conditions_and_comments' => [ - '/* testMatchWithDuplicateConditionsWithComments */', - 12, - 59, - ], - 'nested_match_outer' => [ - '/* testNestedMatchOuter */', - 6, - 33, - ], - 'nested_match_inner' => [ - '/* testNestedMatchInner */', - 6, - 14, - ], - 'ternary_condition' => [ - '/* testMatchInTernaryCondition */', - 6, - 21, - ], - 'ternary_then' => [ - '/* testMatchInTernaryThen */', - 6, - 21, - ], - 'ternary_else' => [ - '/* testMatchInTernaryElse */', - 6, - 21, - ], - 'array_value' => [ - '/* testMatchInArrayValue */', - 6, - 21, - ], - 'array_key' => [ - '/* testMatchInArrayKey */', - 6, - 21, - ], - 'returning_array' => [ - '/* testMatchreturningArray */', - 6, - 125, - ], - 'nested_in_switch_case_1' => [ - '/* testMatchWithDefaultNestedInSwitchCase1 */', - 6, - 25, - ], - 'nested_in_switch_case_2' => [ - '/* testMatchWithDefaultNestedInSwitchCase2 */', - 6, - 25, - ], - 'nested_in_switch_default' => [ - '/* testMatchWithDefaultNestedInSwitchDefault */', - 6, - 25, - ], - 'match_with_nested_switch' => [ - '/* testMatchContainingSwitch */', - 6, - 180, - ], - 'no_cases' => [ - '/* testMatchNoCases */', - 6, - 7, - ], - 'multi_default' => [ - '/* testMatchMultiDefault */', - 6, - 40, - ], - ]; - - }//end dataMatchExpression() - - - /** - * Verify that "match" keywords which are not match control structures get tokenized as T_STRING - * and don't have the extra token array indexes. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to look for. - * - * @dataProvider dataNotAMatchStructure - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNotAMatchStructure($testMarker, $testContent='match') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); - $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); - $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); - $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); - - $next = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($token + 1), null, true); - if ($next !== false && $tokens[$next]['code'] === T_OPEN_PARENTHESIS) { - $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set for opener after'); - } - - }//end testNotAMatchStructure() - - - /** - * Data provider. - * - * @see testNotAMatchStructure() - * - * @return array - */ - public function dataNotAMatchStructure() - { - return [ - 'static_method_call' => ['/* testNoMatchStaticMethodCall */'], - 'class_constant_access' => [ - '/* testNoMatchClassConstantAccess */', - 'MATCH', - ], - 'class_constant_array_access' => [ - '/* testNoMatchClassConstantArrayAccessMixedCase */', - 'Match', - ], - 'method_call' => ['/* testNoMatchMethodCall */'], - 'method_call_uppercase' => [ - '/* testNoMatchMethodCallUpper */', - 'MATCH', - ], - 'property_access' => ['/* testNoMatchPropertyAccess */'], - 'namespaced_function_call' => ['/* testNoMatchNamespacedFunctionCall */'], - 'namespace_operator_function_call' => ['/* testNoMatchNamespaceOperatorFunctionCall */'], - 'interface_method_declaration' => ['/* testNoMatchInterfaceMethodDeclaration */'], - 'class_constant_declaration' => ['/* testNoMatchClassConstantDeclarationLower */'], - 'class_method_declaration' => ['/* testNoMatchClassMethodDeclaration */'], - 'property_assigment' => ['/* testNoMatchPropertyAssignment */'], - 'class_instantiation' => [ - '/* testNoMatchClassInstantiation */', - 'Match', - ], - 'anon_class_method_declaration' => [ - '/* testNoMatchAnonClassMethodDeclaration */', - 'maTCH', - ], - 'class_declaration' => [ - '/* testNoMatchClassDeclaration */', - 'Match', - ], - 'interface_declaration' => [ - '/* testNoMatchInterfaceDeclaration */', - 'Match', - ], - 'trait_declaration' => [ - '/* testNoMatchTraitDeclaration */', - 'Match', - ], - 'constant_declaration' => [ - '/* testNoMatchConstantDeclaration */', - 'MATCH', - ], - 'function_declaration' => ['/* testNoMatchFunctionDeclaration */'], - 'namespace_declaration' => [ - '/* testNoMatchNamespaceDeclaration */', - 'Match', - ], - 'class_extends_declaration' => [ - '/* testNoMatchExtendedClassDeclaration */', - 'Match', - ], - 'class_implements_declaration' => [ - '/* testNoMatchImplementedClassDeclaration */', - 'Match', - ], - 'use_statement' => [ - '/* testNoMatchInUseStatement */', - 'Match', - ], - 'unsupported_inline_control_structure' => ['/* testNoMatchMissingCurlies */'], - 'unsupported_alternative_syntax' => ['/* testNoMatchAlternativeSyntax */'], - 'live_coding' => ['/* testLiveCoding */'], - ]; - - }//end dataNotAMatchStructure() - - - /** - * Verify that the tokenization of switch structures is not affected by the backfill. - * - * @param string $testMarker The comment prefacing the target token. - * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. - * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. - * - * @dataProvider dataSwitchExpression - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testSwitchExpression($testMarker, $openerOffset, $closerOffset) - { - $token = $this->getTargetToken($testMarker, T_SWITCH); - - $this->scopeTestHelper($token, $openerOffset, $closerOffset); - $this->parenthesisTestHelper($token); - - }//end testSwitchExpression() - - - /** - * Data provider. - * - * @see testSwitchExpression() - * - * @return array - */ - public function dataSwitchExpression() - { - return [ - 'switch_containing_match' => [ - '/* testSwitchContainingMatch */', - 6, - 174, - ], - 'match_containing_switch_1' => [ - '/* testSwitchNestedInMatch1 */', - 5, - 63, - ], - 'match_containing_switch_2' => [ - '/* testSwitchNestedInMatch2 */', - 5, - 63, - ], - ]; - - }//end dataSwitchExpression() - - - /** - * Verify that the tokenization of a switch case/default structure containing a match structure - * or contained *in* a match structure is not affected by the backfill. - * - * @param string $testMarker The comment prefacing the target token. - * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. - * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. - * - * @dataProvider dataSwitchCaseVersusMatch - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testSwitchCaseVersusMatch($testMarker, $openerOffset, $closerOffset) - { - $token = $this->getTargetToken($testMarker, [T_CASE, T_DEFAULT]); - - $this->scopeTestHelper($token, $openerOffset, $closerOffset); - - }//end testSwitchCaseVersusMatch() - - - /** - * Data provider. - * - * @see testSwitchCaseVersusMatch() - * - * @return array - */ - public function dataSwitchCaseVersusMatch() - { - return [ - 'switch_with_nested_match_case_1' => [ - '/* testMatchWithDefaultNestedInSwitchCase1 */', - 3, - 55, - ], - 'switch_with_nested_match_case_2' => [ - '/* testMatchWithDefaultNestedInSwitchCase2 */', - 4, - 21, - ], - 'switch_with_nested_match_default_case' => [ - '/* testMatchWithDefaultNestedInSwitchDefault */', - 1, - 38, - ], - 'match_with_nested_switch_case' => [ - '/* testSwitchDefaultNestedInMatchCase */', - 1, - 18, - ], - 'match_with_nested_switch_default_case' => [ - '/* testSwitchDefaultNestedInMatchDefault */', - 1, - 20, - ], - ]; - - }//end dataSwitchCaseVersusMatch() - - - /** - * Helper function to verify that all scope related array indexes for a control structure - * are set correctly. - * - * @param string $token The control structure token to check. - * @param int $openerOffset The expected offset of the scope opener in relation to - * the control structure token. - * @param int $closerOffset The expected offset of the scope closer in relation to - * the control structure token. - * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. - * This should be set to "true" when testing nested arrow functions, - * where the "inner" arrow function shares a scope closer with the - * "outer" arrow function, as the 'scope_condition' for the scope closer - * of the "inner" arrow function will point to the "outer" arrow function. - * - * @return void - */ - private function scopeTestHelper($token, $openerOffset, $closerOffset, $skipScopeCloserCheck=false) - { - $tokens = self::$phpcsFile->getTokens(); - $tokenArray = $tokens[$token]; - $tokenType = $tokenArray['type']; - $expectedScopeOpener = ($token + $openerOffset); - $expectedScopeCloser = ($token + $closerOffset); - - $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); - $this->assertSame($token, $tokenArray['scope_condition'], 'Scope condition is not the '.$tokenType.' token'); - $this->assertSame($expectedScopeOpener, $tokenArray['scope_opener'], 'Scope opener of the '.$tokenType.' token incorrect'); - $this->assertSame($expectedScopeCloser, $tokenArray['scope_closer'], 'Scope closer of the '.$tokenType.' token incorrect'); - - $opener = $tokenArray['scope_opener']; - $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); - $this->assertSame($token, $tokens[$opener]['scope_condition'], 'Opener scope condition is not the '.$tokenType.' token'); - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], $tokenType.' opener scope opener token incorrect'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], $tokenType.' opener scope closer token incorrect'); - - $closer = $tokenArray['scope_closer']; - $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); - if ($skipScopeCloserCheck === false) { - $this->assertSame($token, $tokens[$closer]['scope_condition'], 'Closer scope condition is not the '.$tokenType.' token'); - } - - $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], $tokenType.' closer scope opener token incorrect'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], $tokenType.' closer scope closer token incorrect'); - - if (($opener + 1) !== $closer) { - for ($i = ($opener + 1); $i < $closer; $i++) { - $this->assertArrayHasKey( - $token, - $tokens[$i]['conditions'], - $tokenType.' condition not added for token belonging to the '.$tokenType.' structure' - ); - } - } - - }//end scopeTestHelper() - - - /** - * Helper function to verify that all parenthesis related array indexes for a control structure - * token are set correctly. - * - * @param int $token The position of the control structure token. - * - * @return void - */ - private function parenthesisTestHelper($token) - { - $tokens = self::$phpcsFile->getTokens(); - $tokenArray = $tokens[$token]; - $tokenType = $tokenArray['type']; - - $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); - $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); - $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); - $this->assertSame($token, $tokenArray['parenthesis_owner'], 'Parenthesis owner is not the '.$tokenType.' token'); - - $opener = $tokenArray['parenthesis_opener']; - $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener], 'Opening parenthesis owner is not set'); - $this->assertSame($token, $tokens[$opener]['parenthesis_owner'], 'Opening parenthesis owner is not the '.$tokenType.' token'); - - $closer = $tokenArray['parenthesis_closer']; - $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer], 'Closing parenthesis owner is not set'); - $this->assertSame($token, $tokens[$closer]['parenthesis_owner'], 'Closing parenthesis owner is not the '.$tokenType.' token'); - - }//end parenthesisTestHelper() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php deleted file mode 100644 index 645088fd6..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php +++ /dev/null @@ -1,420 +0,0 @@ - - * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillNumericSeparatorTest extends AbstractMethodUnitTest -{ - - - /** - * Test that numbers using numeric separators are tokenized correctly. - * - * @param array $testData The data required for the specific test case. - * - * @dataProvider dataTestBackfill - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testBackfill($testData) - { - $tokens = self::$phpcsFile->getTokens(); - $number = $this->getTargetToken($testData['marker'], [T_LNUMBER, T_DNUMBER]); - - $this->assertSame(constant($testData['type']), $tokens[$number]['code']); - $this->assertSame($testData['type'], $tokens[$number]['type']); - $this->assertSame($testData['value'], $tokens[$number]['content']); - - }//end testBackfill() - - - /** - * Data provider. - * - * @see testBackfill() - * - * @return array - */ - public function dataTestBackfill() - { - $testHexType = 'T_LNUMBER'; - if (PHP_INT_MAX < 0xCAFEF00D) { - $testHexType = 'T_DNUMBER'; - } - - $testHexMultipleType = 'T_LNUMBER'; - if (PHP_INT_MAX < 0x42726F776E) { - $testHexMultipleType = 'T_DNUMBER'; - } - - $testIntMoreThanMaxType = 'T_LNUMBER'; - if (PHP_INT_MAX < 10223372036854775807) { - $testIntMoreThanMaxType = 'T_DNUMBER'; - } - - return [ - [ - [ - 'marker' => '/* testSimpleLNumber */', - 'type' => 'T_LNUMBER', - 'value' => '1_000_000_000', - ], - ], - [ - [ - 'marker' => '/* testSimpleDNumber */', - 'type' => 'T_DNUMBER', - 'value' => '107_925_284.88', - ], - ], - [ - [ - 'marker' => '/* testFloat */', - 'type' => 'T_DNUMBER', - 'value' => '6.674_083e-11', - ], - ], - [ - [ - 'marker' => '/* testFloat2 */', - 'type' => 'T_DNUMBER', - 'value' => '6.674_083e+11', - ], - ], - [ - [ - 'marker' => '/* testFloat3 */', - 'type' => 'T_DNUMBER', - 'value' => '1_2.3_4e1_23', - ], - ], - [ - [ - 'marker' => '/* testHex */', - 'type' => $testHexType, - 'value' => '0xCAFE_F00D', - ], - ], - [ - [ - 'marker' => '/* testHexMultiple */', - 'type' => $testHexMultipleType, - 'value' => '0x42_72_6F_77_6E', - ], - ], - [ - [ - 'marker' => '/* testHexInt */', - 'type' => 'T_LNUMBER', - 'value' => '0x42_72_6F', - ], - ], - [ - [ - 'marker' => '/* testBinary */', - 'type' => 'T_LNUMBER', - 'value' => '0b0101_1111', - ], - ], - [ - [ - 'marker' => '/* testOctal */', - 'type' => 'T_LNUMBER', - 'value' => '0137_041', - ], - ], - [ - [ - 'marker' => '/* testExplicitOctal */', - 'type' => 'T_LNUMBER', - 'value' => '0o137_041', - ], - ], - [ - [ - 'marker' => '/* testExplicitOctalCapitalised */', - 'type' => 'T_LNUMBER', - 'value' => '0O137_041', - ], - ], - [ - [ - 'marker' => '/* testIntMoreThanMax */', - 'type' => $testIntMoreThanMaxType, - 'value' => '10_223_372_036_854_775_807', - ], - ], - ]; - - }//end dataTestBackfill() - - - /** - * Test that numbers using numeric separators which are considered parse errors and/or - * which aren't relevant to the backfill, do not incorrectly trigger the backfill anyway. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param array $expectedTokens The token type and content of the expected token sequence. - * - * @dataProvider dataNoBackfill - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testNoBackfill($testMarker, $expectedTokens) - { - $tokens = self::$phpcsFile->getTokens(); - $number = $this->getTargetToken($testMarker, [T_LNUMBER, T_DNUMBER]); - - foreach ($expectedTokens as $key => $expectedToken) { - $i = ($number + $key); - $this->assertSame($expectedToken['code'], $tokens[$i]['code']); - $this->assertSame($expectedToken['content'], $tokens[$i]['content']); - } - - }//end testNoBackfill() - - - /** - * Data provider. - * - * @see testBackfill() - * - * @return array - */ - public function dataNoBackfill() - { - return [ - [ - '/* testInvalid1 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '100', - ], - [ - 'code' => T_STRING, - 'content' => '_', - ], - ], - ], - [ - '/* testInvalid2 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '1', - ], - [ - 'code' => T_STRING, - 'content' => '__1', - ], - ], - ], - [ - '/* testInvalid3 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '1', - ], - [ - 'code' => T_STRING, - 'content' => '_', - ], - [ - 'code' => T_DNUMBER, - 'content' => '.0', - ], - ], - ], - [ - '/* testInvalid4 */', - [ - [ - 'code' => T_DNUMBER, - 'content' => '1.', - ], - [ - 'code' => T_STRING, - 'content' => '_0', - ], - ], - ], - [ - '/* testInvalid5 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '0', - ], - [ - 'code' => T_STRING, - 'content' => 'x_123', - ], - ], - ], - [ - '/* testInvalid6 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '0', - ], - [ - 'code' => T_STRING, - 'content' => 'b_101', - ], - ], - ], - [ - '/* testInvalid7 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '1', - ], - [ - 'code' => T_STRING, - 'content' => '_e2', - ], - ], - ], - [ - '/* testInvalid8 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '1', - ], - [ - 'code' => T_STRING, - 'content' => 'e_2', - ], - ], - ], - [ - '/* testInvalid9 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '107_925_284', - ], - [ - 'code' => T_WHITESPACE, - 'content' => ' ', - ], - [ - 'code' => T_DNUMBER, - 'content' => '.88', - ], - ], - ], - [ - '/* testInvalid10 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '107_925_284', - ], - [ - 'code' => T_COMMENT, - 'content' => '/*comment*/', - ], - [ - 'code' => T_DNUMBER, - 'content' => '.88', - ], - ], - ], - [ - '/* testInvalid11 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '0', - ], - [ - 'code' => T_STRING, - 'content' => 'o_137', - ], - ], - ], - [ - '/* testInvalid12 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '0', - ], - [ - 'code' => T_STRING, - 'content' => 'O_41', - ], - ], - ], - [ - '/* testCalc1 */', - [ - [ - 'code' => T_LNUMBER, - 'content' => '667_083', - ], - [ - 'code' => T_WHITESPACE, - 'content' => ' ', - ], - [ - 'code' => T_MINUS, - 'content' => '-', - ], - [ - 'code' => T_WHITESPACE, - 'content' => ' ', - ], - [ - 'code' => T_LNUMBER, - 'content' => '11', - ], - ], - ], - [ - '/* test Calc2 */', - [ - [ - 'code' => T_DNUMBER, - 'content' => '6.674_08e3', - ], - [ - 'code' => T_WHITESPACE, - 'content' => ' ', - ], - [ - 'code' => T_PLUS, - 'content' => '+', - ], - [ - 'code' => T_WHITESPACE, - 'content' => ' ', - ], - [ - 'code' => T_LNUMBER, - 'content' => '11', - ], - ], - ], - ]; - - }//end dataNoBackfill() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc deleted file mode 100644 index eaf0b4b3c..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc +++ /dev/null @@ -1,100 +0,0 @@ -readonly = 'foo'; - - /* testReadonlyPropertyInTernaryOperator */ - $isReadonly = $this->readonly ? true : false; - } -} - -/* testReadonlyUsedAsFunctionName */ -function readonly() -{ -} - -/* testReadonlyUsedAsNamespaceName */ -namespace Readonly; -/* testReadonlyUsedAsPartOfNamespaceName */ -namespace My\Readonly\Collection; -/* testReadonlyAsFunctionCall */ -$var = readonly($a, $b); -/* testClassConstantFetchWithReadonlyAsConstantName */ -echo ClassName::READONLY; - -/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */ -$var = readonly /* comment */ (); - -/* testParseErrorLiveCoding */ -// This must be the last test in the file. -readonly diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php deleted file mode 100644 index dddc18ebc..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php +++ /dev/null @@ -1,236 +0,0 @@ - - * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillReadonlyTest extends AbstractMethodUnitTest -{ - - - /** - * Test that the "readonly" keyword is tokenized as such. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $testContent The token content to look for. - * - * @dataProvider dataReadonly - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testReadonly($testMarker, $testContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); - $this->assertSame(T_READONLY, $tokens[$target]['code']); - $this->assertSame('T_READONLY', $tokens[$target]['type']); - - }//end testReadonly() - - - /** - * Data provider. - * - * @see testReadonly() - * - * @return array - */ - public function dataReadonly() - { - return [ - [ - '/* testReadonlyProperty */', - 'readonly', - ], - [ - '/* testVarReadonlyProperty */', - 'readonly', - ], - [ - '/* testReadonlyVarProperty */', - 'readonly', - ], - [ - '/* testStaticReadonlyProperty */', - 'readonly', - ], - [ - '/* testReadonlyStaticProperty */', - 'readonly', - ], - [ - '/* testConstReadonlyProperty */', - 'readonly', - ], - [ - '/* testReadonlyPropertyWithoutType */', - 'readonly', - ], - [ - '/* testPublicReadonlyProperty */', - 'readonly', - ], - [ - '/* testProtectedReadonlyProperty */', - 'readonly', - ], - [ - '/* testPrivateReadonlyProperty */', - 'readonly', - ], - [ - '/* testPublicReadonlyPropertyWithReadonlyFirst */', - 'readonly', - ], - [ - '/* testProtectedReadonlyPropertyWithReadonlyFirst */', - 'readonly', - ], - [ - '/* testPrivateReadonlyPropertyWithReadonlyFirst */', - 'readonly', - ], - [ - '/* testReadonlyWithCommentsInDeclaration */', - 'readonly', - ], - [ - '/* testReadonlyWithNullableProperty */', - 'readonly', - ], - [ - '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullFirst */', - 'readonly', - ], - [ - '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullLast */', - 'readonly', - ], - [ - '/* testReadonlyPropertyWithArrayTypeHint */', - 'readonly', - ], - [ - '/* testReadonlyPropertyWithSelfTypeHint */', - 'readonly', - ], - [ - '/* testReadonlyPropertyWithParentTypeHint */', - 'readonly', - ], - [ - '/* testReadonlyPropertyWithFullyQualifiedTypeHint */', - 'readonly', - ], - [ - '/* testReadonlyIsCaseInsensitive */', - 'ReAdOnLy', - ], - [ - '/* testReadonlyConstructorPropertyPromotion */', - 'readonly', - ], - [ - '/* testReadonlyConstructorPropertyPromotionWithReference */', - 'ReadOnly', - ], - [ - '/* testReadonlyPropertyInAnonymousClass */', - 'readonly', - ], - [ - '/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */', - 'readonly', - ], - [ - '/* testParseErrorLiveCoding */', - 'readonly', - ], - ]; - - }//end dataReadonly() - - - /** - * Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $testContent The token content to look for. - * - * @dataProvider dataNotReadonly - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNotReadonly($testMarker, $testContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); - - }//end testNotReadonly() - - - /** - * Data provider. - * - * @see testNotReadonly() - * - * @return array - */ - public function dataNotReadonly() - { - return [ - [ - '/* testReadonlyUsedAsClassConstantName */', - 'READONLY', - ], - [ - '/* testReadonlyUsedAsMethodName */', - 'readonly', - ], - [ - '/* testReadonlyUsedAsPropertyName */', - 'readonly', - ], - [ - '/* testReadonlyPropertyInTernaryOperator */', - 'readonly', - ], - [ - '/* testReadonlyUsedAsFunctionName */', - 'readonly', - ], - [ - '/* testReadonlyUsedAsNamespaceName */', - 'Readonly', - ], - [ - '/* testReadonlyUsedAsPartOfNamespaceName */', - 'Readonly', - ], - [ - '/* testReadonlyAsFunctionCall */', - 'readonly', - ], - [ - '/* testClassConstantFetchWithReadonlyAsConstantName */', - 'READONLY', - ], - ]; - - }//end dataNotReadonly() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc deleted file mode 100644 index bfdbdc18c..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc +++ /dev/null @@ -1,134 +0,0 @@ - $param | $int; - -/* testTypeUnionArrowReturnType */ -$arrowWithReturnType = fn ($param) : int|null => $param * 10; - -/* testBitwiseOrInArrayKey */ -$array = array( - A | B => /* testBitwiseOrInArrayValue */ B | C -); - -/* testBitwiseOrInShortArrayKey */ -$array = [ - A | B => /* testBitwiseOrInShortArrayValue */ B | C -]; - -/* testBitwiseOrTryCatch */ -try { -} catch ( ExceptionA | ExceptionB $e ) { -} - -/* testBitwiseOrNonArrowFnFunctionCall */ -$obj->fn($something | $else); - -/* testTypeUnionNonArrowFunctionDeclaration */ -function &fn(int|false $something) {} - -/* testLiveCoding */ -// Intentional parse error. This has to be the last test in the file. -return function( type| diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php deleted file mode 100644 index d56e7340a..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php +++ /dev/null @@ -1,138 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BitwiseOrTest extends AbstractMethodUnitTest -{ - - - /** - * Test that non-union type bitwise or tokens are still tokenized as bitwise or. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataBitwiseOr - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testBitwiseOr($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $opener = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); - $this->assertSame(T_BITWISE_OR, $tokens[$opener]['code']); - $this->assertSame('T_BITWISE_OR', $tokens[$opener]['type']); - - }//end testBitwiseOr() - - - /** - * Data provider. - * - * @see testBitwiseOr() - * - * @return array - */ - public function dataBitwiseOr() - { - return [ - ['/* testBitwiseOr1 */'], - ['/* testBitwiseOr2 */'], - ['/* testBitwiseOrPropertyDefaultValue */'], - ['/* testBitwiseOrParamDefaultValue */'], - ['/* testBitwiseOr3 */'], - ['/* testBitwiseOrClosureParamDefault */'], - ['/* testBitwiseOrArrowParamDefault */'], - ['/* testBitwiseOrArrowExpression */'], - ['/* testBitwiseOrInArrayKey */'], - ['/* testBitwiseOrInArrayValue */'], - ['/* testBitwiseOrInShortArrayKey */'], - ['/* testBitwiseOrInShortArrayValue */'], - ['/* testBitwiseOrTryCatch */'], - ['/* testBitwiseOrNonArrowFnFunctionCall */'], - ['/* testLiveCoding */'], - ]; - - }//end dataBitwiseOr() - - - /** - * Test that bitwise or tokens when used as part of a union type are tokenized as `T_TYPE_UNION`. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataTypeUnion - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testTypeUnion($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $opener = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); - $this->assertSame(T_TYPE_UNION, $tokens[$opener]['code']); - $this->assertSame('T_TYPE_UNION', $tokens[$opener]['type']); - - }//end testTypeUnion() - - - /** - * Data provider. - * - * @see testTypeUnion() - * - * @return array - */ - public function dataTypeUnion() - { - return [ - ['/* testTypeUnionPropertySimple */'], - ['/* testTypeUnionPropertyReverseModifierOrder */'], - ['/* testTypeUnionPropertyMulti1 */'], - ['/* testTypeUnionPropertyMulti2 */'], - ['/* testTypeUnionPropertyMulti3 */'], - ['/* testTypeUnionPropertyNamespaceRelative */'], - ['/* testTypeUnionPropertyPartiallyQualified */'], - ['/* testTypeUnionPropertyFullyQualified */'], - ['/* testTypeUnionPropertyWithReadOnlyKeyword */'], - ['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'], - ['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'], - ['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'], - ['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'], - ['/* testTypeUnionParam1 */'], - ['/* testTypeUnionParam2 */'], - ['/* testTypeUnionParam3 */'], - ['/* testTypeUnionParamNamespaceRelative */'], - ['/* testTypeUnionParamPartiallyQualified */'], - ['/* testTypeUnionParamFullyQualified */'], - ['/* testTypeUnionReturnType */'], - ['/* testTypeUnionConstructorPropertyPromotion */'], - ['/* testTypeUnionAbstractMethodReturnType1 */'], - ['/* testTypeUnionAbstractMethodReturnType2 */'], - ['/* testTypeUnionReturnTypeNamespaceRelative */'], - ['/* testTypeUnionReturnPartiallyQualified */'], - ['/* testTypeUnionReturnFullyQualified */'], - ['/* testTypeUnionClosureParamIllegalNullable */'], - ['/* testTypeUnionWithReference */'], - ['/* testTypeUnionWithSpreadOperator */'], - ['/* testTypeUnionClosureReturn */'], - ['/* testTypeUnionArrowParam */'], - ['/* testTypeUnionArrowReturnType */'], - ['/* testTypeUnionNonArrowFunctionDeclaration */'], - ]; - - }//end dataTypeUnion() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php deleted file mode 100644 index a747e573c..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php +++ /dev/null @@ -1,509 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -use PHP_CodeSniffer\Util\Tokens; - -class ContextSensitiveKeywordsTest extends AbstractMethodUnitTest -{ - - - /** - * Test that context sensitive keyword is tokenized as string when it should be string. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataStrings - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testStrings($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_STRING])); - - $this->assertSame(T_STRING, $tokens[$token]['code']); - $this->assertSame('T_STRING', $tokens[$token]['type']); - - }//end testStrings() - - - /** - * Data provider. - * - * @see testStrings() - * - * @return array - */ - public function dataStrings() - { - return [ - ['/* testAbstract */'], - ['/* testArray */'], - ['/* testAs */'], - ['/* testBreak */'], - ['/* testCallable */'], - ['/* testCase */'], - ['/* testCatch */'], - ['/* testClass */'], - ['/* testClone */'], - ['/* testConst */'], - ['/* testContinue */'], - ['/* testDeclare */'], - ['/* testDefault */'], - ['/* testDo */'], - ['/* testEcho */'], - ['/* testElse */'], - ['/* testElseIf */'], - ['/* testEmpty */'], - ['/* testEndDeclare */'], - ['/* testEndFor */'], - ['/* testEndForeach */'], - ['/* testEndIf */'], - ['/* testEndSwitch */'], - ['/* testEndWhile */'], - ['/* testEnum */'], - ['/* testEval */'], - ['/* testExit */'], - ['/* testExtends */'], - ['/* testFinal */'], - ['/* testFinally */'], - ['/* testFn */'], - ['/* testFor */'], - ['/* testForeach */'], - ['/* testFunction */'], - ['/* testGlobal */'], - ['/* testGoto */'], - ['/* testIf */'], - ['/* testImplements */'], - ['/* testInclude */'], - ['/* testIncludeOnce */'], - ['/* testInstanceOf */'], - ['/* testInsteadOf */'], - ['/* testInterface */'], - ['/* testIsset */'], - ['/* testList */'], - ['/* testMatch */'], - ['/* testNamespace */'], - ['/* testNew */'], - ['/* testParent */'], - ['/* testPrint */'], - ['/* testPrivate */'], - ['/* testProtected */'], - ['/* testPublic */'], - ['/* testReadonly */'], - ['/* testRequire */'], - ['/* testRequireOnce */'], - ['/* testReturn */'], - ['/* testSelf */'], - ['/* testStatic */'], - ['/* testSwitch */'], - ['/* testThrows */'], - ['/* testTrait */'], - ['/* testTry */'], - ['/* testUnset */'], - ['/* testUse */'], - ['/* testVar */'], - ['/* testWhile */'], - ['/* testYield */'], - ['/* testYieldFrom */'], - ['/* testAnd */'], - ['/* testOr */'], - ['/* testXor */'], - - ['/* testKeywordAfterNamespaceShouldBeString */'], - ['/* testNamespaceNameIsString1 */'], - ['/* testNamespaceNameIsString2 */'], - ['/* testNamespaceNameIsString3 */'], - - ['/* testKeywordAfterFunctionShouldBeString */'], - ['/* testKeywordAfterFunctionByRefShouldBeString */'], - ]; - - }//end dataStrings() - - - /** - * Test that context sensitive keyword is tokenized as keyword when it should be keyword. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $expectedTokenType The expected token type. - * - * @dataProvider dataKeywords - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testKeywords($testMarker, $expectedTokenType) - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_ANON_CLASS, T_MATCH_DEFAULT, T_PARENT, T_SELF, T_STRING])); - - $this->assertSame(constant($expectedTokenType), $tokens[$token]['code']); - $this->assertSame($expectedTokenType, $tokens[$token]['type']); - - }//end testKeywords() - - - /** - * Data provider. - * - * @see testKeywords() - * - * @return array - */ - public function dataKeywords() - { - return [ - [ - '/* testNamespaceIsKeyword */', - 'T_NAMESPACE', - ], - [ - '/* testAbstractIsKeyword */', - 'T_ABSTRACT', - ], - [ - '/* testClassIsKeyword */', - 'T_CLASS', - ], - [ - '/* testExtendsIsKeyword */', - 'T_EXTENDS', - ], - [ - '/* testImplementsIsKeyword */', - 'T_IMPLEMENTS', - ], - [ - '/* testUseIsKeyword */', - 'T_USE', - ], - [ - '/* testInsteadOfIsKeyword */', - 'T_INSTEADOF', - ], - [ - '/* testAsIsKeyword */', - 'T_AS', - ], - [ - '/* testConstIsKeyword */', - 'T_CONST', - ], - [ - '/* testPrivateIsKeyword */', - 'T_PRIVATE', - ], - [ - '/* testProtectedIsKeyword */', - 'T_PROTECTED', - ], - [ - '/* testPublicIsKeyword */', - 'T_PUBLIC', - ], - [ - '/* testVarIsKeyword */', - 'T_VAR', - ], - [ - '/* testStaticIsKeyword */', - 'T_STATIC', - ], - [ - '/* testReadonlyIsKeyword */', - 'T_READONLY', - ], - [ - '/* testFinalIsKeyword */', - 'T_FINAL', - ], - [ - '/* testFunctionIsKeyword */', - 'T_FUNCTION', - ], - [ - '/* testCallableIsKeyword */', - 'T_CALLABLE', - ], - [ - '/* testSelfIsKeyword */', - 'T_SELF', - ], - [ - '/* testParentIsKeyword */', - 'T_PARENT', - ], - [ - '/* testReturnIsKeyword */', - 'T_RETURN', - ], - - [ - '/* testInterfaceIsKeyword */', - 'T_INTERFACE', - ], - [ - '/* testTraitIsKeyword */', - 'T_TRAIT', - ], - [ - '/* testEnumIsKeyword */', - 'T_ENUM', - ], - - [ - '/* testNewIsKeyword */', - 'T_NEW', - ], - [ - '/* testInstanceOfIsKeyword */', - 'T_INSTANCEOF', - ], - [ - '/* testCloneIsKeyword */', - 'T_CLONE', - ], - - [ - '/* testIfIsKeyword */', - 'T_IF', - ], - [ - '/* testEmptyIsKeyword */', - 'T_EMPTY', - ], - [ - '/* testElseIfIsKeyword */', - 'T_ELSEIF', - ], - [ - '/* testElseIsKeyword */', - 'T_ELSE', - ], - [ - '/* testEndIfIsKeyword */', - 'T_ENDIF', - ], - - [ - '/* testForIsKeyword */', - 'T_FOR', - ], - [ - '/* testEndForIsKeyword */', - 'T_ENDFOR', - ], - - [ - '/* testForeachIsKeyword */', - 'T_FOREACH', - ], - [ - '/* testEndForeachIsKeyword */', - 'T_ENDFOREACH', - ], - - [ - '/* testSwitchIsKeyword */', - 'T_SWITCH', - ], - [ - '/* testCaseIsKeyword */', - 'T_CASE', - ], - [ - '/* testDefaultIsKeyword */', - 'T_DEFAULT', - ], - [ - '/* testEndSwitchIsKeyword */', - 'T_ENDSWITCH', - ], - [ - '/* testBreakIsKeyword */', - 'T_BREAK', - ], - [ - '/* testContinueIsKeyword */', - 'T_CONTINUE', - ], - - [ - '/* testDoIsKeyword */', - 'T_DO', - ], - [ - '/* testWhileIsKeyword */', - 'T_WHILE', - ], - [ - '/* testEndWhileIsKeyword */', - 'T_ENDWHILE', - ], - - [ - '/* testTryIsKeyword */', - 'T_TRY', - ], - [ - '/* testThrowIsKeyword */', - 'T_THROW', - ], - [ - '/* testCatchIsKeyword */', - 'T_CATCH', - ], - [ - '/* testFinallyIsKeyword */', - 'T_FINALLY', - ], - - [ - '/* testGlobalIsKeyword */', - 'T_GLOBAL', - ], - [ - '/* testEchoIsKeyword */', - 'T_ECHO', - ], - [ - '/* testPrintIsKeyword */', - 'T_PRINT', - ], - [ - '/* testDieIsKeyword */', - 'T_EXIT', - ], - [ - '/* testEvalIsKeyword */', - 'T_EVAL', - ], - [ - '/* testExitIsKeyword */', - 'T_EXIT', - ], - [ - '/* testIssetIsKeyword */', - 'T_ISSET', - ], - [ - '/* testUnsetIsKeyword */', - 'T_UNSET', - ], - - [ - '/* testIncludeIsKeyword */', - 'T_INCLUDE', - ], - [ - '/* testIncludeOnceIsKeyword */', - 'T_INCLUDE_ONCE', - ], - [ - '/* testRequireIsKeyword */', - 'T_REQUIRE', - ], - [ - '/* testRequireOnceIsKeyword */', - 'T_REQUIRE_ONCE', - ], - - [ - '/* testListIsKeyword */', - 'T_LIST', - ], - [ - '/* testGotoIsKeyword */', - 'T_GOTO', - ], - [ - '/* testMatchIsKeyword */', - 'T_MATCH', - ], - [ - '/* testMatchDefaultIsKeyword */', - 'T_MATCH_DEFAULT', - ], - [ - '/* testFnIsKeyword */', - 'T_FN', - ], - - [ - '/* testYieldIsKeyword */', - 'T_YIELD', - ], - [ - '/* testYieldFromIsKeyword */', - 'T_YIELD_FROM', - ], - - [ - '/* testDeclareIsKeyword */', - 'T_DECLARE', - ], - [ - '/* testEndDeclareIsKeyword */', - 'T_ENDDECLARE', - ], - - [ - '/* testAndIsKeyword */', - 'T_LOGICAL_AND', - ], - [ - '/* testOrIsKeyword */', - 'T_LOGICAL_OR', - ], - [ - '/* testXorIsKeyword */', - 'T_LOGICAL_XOR', - ], - - [ - '/* testAnonymousClassIsKeyword */', - 'T_ANON_CLASS', - ], - [ - '/* testExtendsInAnonymousClassIsKeyword */', - 'T_EXTENDS', - ], - [ - '/* testImplementsInAnonymousClassIsKeyword */', - 'T_IMPLEMENTS', - ], - [ - '/* testClassInstantiationParentIsKeyword */', - 'T_PARENT', - ], - [ - '/* testClassInstantiationSelfIsKeyword */', - 'T_SELF', - ], - [ - '/* testClassInstantiationStaticIsKeyword */', - 'T_STATIC', - ], - [ - '/* testNamespaceInNameIsKeyword */', - 'T_NAMESPACE', - ], - ]; - - }//end dataKeywords() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php deleted file mode 100644 index 9a5b061a0..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php +++ /dev/null @@ -1,302 +0,0 @@ - - * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class DefaultKeywordTest extends AbstractMethodUnitTest -{ - - - /** - * Test the retokenization of the `default` keyword for match structure to `T_MATCH_DEFAULT`. - * - * Note: Cases and default structures within a match structure do *NOT* get case/default scope - * conditions, in contrast to case and default structures in switch control structures. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to look for. - * - * @dataProvider dataMatchDefault - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap - * - * @return void - */ - public function testMatchDefault($testMarker, $testContent='default') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame(T_MATCH_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (code)'); - $this->assertSame('T_MATCH_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (type)'); - - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - - }//end testMatchDefault() - - - /** - * Data provider. - * - * @see testMatchDefault() - * - * @return array - */ - public function dataMatchDefault() - { - return [ - 'simple_match_default' => ['/* testSimpleMatchDefault */'], - 'match_default_in_switch_case_1' => ['/* testMatchDefaultNestedInSwitchCase1 */'], - 'match_default_in_switch_case_2' => ['/* testMatchDefaultNestedInSwitchCase2 */'], - 'match_default_in_switch_default' => ['/* testMatchDefaultNestedInSwitchDefault */'], - 'match_default_containing_switch' => ['/* testMatchDefault */'], - - 'match_default_with_nested_long_array_and_default_key' => [ - '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', - 'DEFAULT', - ], - 'match_default_with_nested_long_array_and_default_key_2' => [ - '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', - 'DEFAULT', - ], - 'match_default_with_nested_short_array_and_default_key' => [ - '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', - 'DEFAULT', - ], - 'match_default_with_nested_short_array_and_default_key_2' => [ - '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', - 'DEFAULT', - ], - 'match_default_in_long_array' => [ - '/* testMatchDefaultNestedInLongArray */', - 'DEFAULT', - ], - 'match_default_in_short_array' => [ - '/* testMatchDefaultNestedInShortArray */', - 'DEFAULT', - ], - ]; - - }//end dataMatchDefault() - - - /** - * Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively - * impact the tokenization of `T_DEFAULT` tokens in switch control structures. - * - * Note: Cases and default structures within a switch control structure *do* get case/default scope - * conditions. - * - * @param string $testMarker The comment prefacing the target token. - * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. - * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. - * @param int|null $conditionStop The expected offset at which tokens stop having T_DEFAULT as a scope condition. - * @param string $testContent The token content to look for. - * - * @dataProvider dataSwitchDefault - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap - * - * @return void - */ - public function testSwitchDefault($testMarker, $openerOffset, $closerOffset, $conditionStop=null, $testContent='default') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); - $tokenArray = $tokens[$token]; - $expectedScopeOpener = ($token + $openerOffset); - $expectedScopeCloser = ($token + $closerOffset); - - $this->assertSame(T_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (code)'); - $this->assertSame('T_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (type)'); - - $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); - $this->assertSame($token, $tokenArray['scope_condition'], 'Scope condition is not the T_DEFAULT token'); - $this->assertSame($expectedScopeOpener, $tokenArray['scope_opener'], 'Scope opener of the T_DEFAULT token incorrect'); - $this->assertSame($expectedScopeCloser, $tokenArray['scope_closer'], 'Scope closer of the T_DEFAULT token incorrect'); - - $opener = $tokenArray['scope_opener']; - $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); - $this->assertSame($token, $tokens[$opener]['scope_condition'], 'Opener scope condition is not the T_DEFAULT token'); - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'T_DEFAULT opener scope opener token incorrect'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'T_DEFAULT opener scope closer token incorrect'); - - $closer = $tokenArray['scope_closer']; - $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); - $this->assertSame($token, $tokens[$closer]['scope_condition'], 'Closer scope condition is not the T_DEFAULT token'); - $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'T_DEFAULT closer scope opener token incorrect'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'T_DEFAULT closer scope closer token incorrect'); - - if (($opener + 1) !== $closer) { - $end = $closer; - if (isset($conditionStop) === true) { - $end = $conditionStop; - } - - for ($i = ($opener + 1); $i < $end; $i++) { - $this->assertArrayHasKey( - $token, - $tokens[$i]['conditions'], - 'T_DEFAULT condition not added for token belonging to the T_DEFAULT structure' - ); - } - } - - }//end testSwitchDefault() - - - /** - * Data provider. - * - * @see testSwitchDefault() - * - * @return array - */ - public function dataSwitchDefault() - { - return [ - 'simple_switch_default' => [ - '/* testSimpleSwitchDefault */', - 1, - 4, - ], - 'simple_switch_default_with_curlies' => [ - // For a default structure with curly braces, the scope opener - // will be the open curly and the closer the close curly. - // However, scope conditions will not be set for open to close, - // but only for the open token up to the "break/return/continue" etc. - '/* testSimpleSwitchDefaultWithCurlies */', - 3, - 12, - 6, - ], - 'switch_default_toplevel' => [ - '/* testSwitchDefault */', - 1, - 43, - ], - 'switch_default_nested_in_match_case' => [ - '/* testSwitchDefaultNestedInMatchCase */', - 1, - 20, - ], - 'switch_default_nested_in_match_default' => [ - '/* testSwitchDefaultNestedInMatchDefault */', - 1, - 18, - ], - ]; - - }//end dataSwitchDefault() - - - /** - * Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively - * impact the tokenization of `T_STRING` tokens with the contents 'default' which aren't in - * actual fact the default keyword. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to look for. - * - * @dataProvider dataNotDefaultKeyword - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); - $tokenArray = $tokens[$token]; - - $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); - $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - - }//end testNotDefaultKeyword() - - - /** - * Data provider. - * - * @see testNotDefaultKeyword() - * - * @return array - */ - public function dataNotDefaultKeyword() - { - return [ - 'class-constant-as-short-array-key' => ['/* testClassConstantAsShortArrayKey */'], - 'class-property-as-short-array-key' => ['/* testClassPropertyAsShortArrayKey */'], - 'namespaced-constant-as-short-array-key' => ['/* testNamespacedConstantAsShortArrayKey */'], - 'fqn-global-constant-as-short-array-key' => ['/* testFQNGlobalConstantAsShortArrayKey */'], - 'class-constant-as-long-array-key' => ['/* testClassConstantAsLongArrayKey */'], - 'class-constant-as-yield-key' => ['/* testClassConstantAsYieldKey */'], - - 'class-constant-as-long-array-key-nested-in-match' => ['/* testClassConstantAsLongArrayKeyNestedInMatch */'], - 'class-constant-as-long-array-key-nested-in-match-2' => ['/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */'], - 'class-constant-as-short-array-key-nested-in-match' => ['/* testClassConstantAsShortArrayKeyNestedInMatch */'], - 'class-constant-as-short-array-key-nested-in-match-2' => ['/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */'], - 'class-constant-as-long-array-key-with-nested-match' => ['/* testClassConstantAsLongArrayKeyWithNestedMatch */'], - 'class-constant-as-short-array-key-with-nested-match' => ['/* testClassConstantAsShortArrayKeyWithNestedMatch */'], - - 'class-constant-in-switch-case' => ['/* testClassConstantInSwitchCase */'], - 'class-property-in-switch-case' => ['/* testClassPropertyInSwitchCase */'], - 'namespaced-constant-in-switch-case' => ['/* testNamespacedConstantInSwitchCase */'], - 'namespace-relative-constant-in-switch-case' => ['/* testNamespaceRelativeConstantInSwitchCase */'], - - 'class-constant-declaration' => ['/* testClassConstant */'], - 'class-method-declaration' => [ - '/* testMethodDeclaration */', - 'default', - ], - ]; - - }//end dataNotDefaultKeyword() - - - /** - * Test a specific edge case where a scope opener would be incorrectly set. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3326 - * - * @return void - */ - public function testIssue3326() - { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken('/* testClassConstant */', [T_SEMICOLON]); - $tokenArray = $tokens[$token]; - - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - - }//end testIssue3326() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php deleted file mode 100644 index cc9fe49ec..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php +++ /dev/null @@ -1,136 +0,0 @@ - - * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class DoubleQuotedStringTest extends AbstractMethodUnitTest -{ - - - /** - * Test that double quoted strings contain the complete string. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $expectedContent The expected content of the double quoted string. - * - * @dataProvider dataDoubleQuotedString - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testDoubleQuotedString($testMarker, $expectedContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, T_DOUBLE_QUOTED_STRING); - $this->assertSame($expectedContent, $tokens[$target]['content']); - - }//end testDoubleQuotedString() - - - /** - * Data provider. - * - * @see testDoubleQuotedString() - * - * @return array - */ - public function dataDoubleQuotedString() - { - return [ - [ - 'testMarker' => '/* testSimple1 */', - 'expectedContent' => '"$foo"', - ], - [ - 'testMarker' => '/* testSimple2 */', - 'expectedContent' => '"{$foo}"', - ], - [ - 'testMarker' => '/* testSimple3 */', - 'expectedContent' => '"${foo}"', - ], - [ - 'testMarker' => '/* testDIM1 */', - 'expectedContent' => '"$foo[bar]"', - ], - [ - 'testMarker' => '/* testDIM2 */', - 'expectedContent' => '"{$foo[\'bar\']}"', - ], - [ - 'testMarker' => '/* testDIM3 */', - 'expectedContent' => '"${foo[\'bar\']}"', - ], - [ - 'testMarker' => '/* testProperty1 */', - 'expectedContent' => '"$foo->bar"', - ], - [ - 'testMarker' => '/* testProperty2 */', - 'expectedContent' => '"{$foo->bar}"', - ], - [ - 'testMarker' => '/* testMethod1 */', - 'expectedContent' => '"{$foo->bar()}"', - ], - [ - 'testMarker' => '/* testClosure1 */', - 'expectedContent' => '"{$foo()}"', - ], - [ - 'testMarker' => '/* testChain1 */', - 'expectedContent' => '"{$foo[\'bar\']->baz()()}"', - ], - [ - 'testMarker' => '/* testVariableVar1 */', - 'expectedContent' => '"${$bar}"', - ], - [ - 'testMarker' => '/* testVariableVar2 */', - 'expectedContent' => '"${(foo)}"', - ], - [ - 'testMarker' => '/* testVariableVar3 */', - 'expectedContent' => '"${foo->bar}"', - ], - [ - 'testMarker' => '/* testNested1 */', - 'expectedContent' => '"${foo["${bar}"]}"', - ], - [ - 'testMarker' => '/* testNested2 */', - 'expectedContent' => '"${foo["${bar[\'baz\']}"]}"', - ], - [ - 'testMarker' => '/* testNested3 */', - 'expectedContent' => '"${foo->{$baz}}"', - ], - [ - 'testMarker' => '/* testNested4 */', - 'expectedContent' => '"${foo->{${\'a\'}}}"', - ], - [ - 'testMarker' => '/* testNested5 */', - 'expectedContent' => '"${foo->{"${\'a\'}"}}"', - ], - [ - 'testMarker' => '/* testParseError */', - 'expectedContent' => '"${foo["${bar -', - ], - ]; - - }//end dataDoubleQuotedString() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php deleted file mode 100644 index 61141da4f..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php +++ /dev/null @@ -1,157 +0,0 @@ - - * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class EnumCaseTest extends AbstractMethodUnitTest -{ - - - /** - * Test that the enum "case" is converted to T_ENUM_CASE. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataEnumCases - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap - * - * @return void - */ - public function testEnumCases($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); - - $this->assertSame(T_ENUM_CASE, $tokens[$enumCase]['code']); - $this->assertSame('T_ENUM_CASE', $tokens[$enumCase]['type']); - - $this->assertArrayNotHasKey('scope_condition', $tokens[$enumCase], 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokens[$enumCase], 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokens[$enumCase], 'Scope closer is set'); - - }//end testEnumCases() - - - /** - * Data provider. - * - * @see testEnumCases() - * - * @return array - */ - public function dataEnumCases() - { - return [ - ['/* testPureEnumCase */'], - ['/* testBackingIntegerEnumCase */'], - ['/* testBackingStringEnumCase */'], - ['/* testEnumCaseInComplexEnum */'], - ['/* testEnumCaseIsCaseInsensitive */'], - ['/* testEnumCaseAfterSwitch */'], - ['/* testEnumCaseAfterSwitchWithEndSwitch */'], - ]; - - }//end dataEnumCases() - - - /** - * Test that "case" that is not enum case is still tokenized as `T_CASE`. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataNotEnumCases - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap - * - * @return void - */ - public function testNotEnumCases($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $case = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); - - $this->assertSame(T_CASE, $tokens[$case]['code']); - $this->assertSame('T_CASE', $tokens[$case]['type']); - - $this->assertArrayHasKey('scope_condition', $tokens[$case], 'Scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$case], 'Scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$case], 'Scope closer is not set'); - - }//end testNotEnumCases() - - - /** - * Data provider. - * - * @see testNotEnumCases() - * - * @return array - */ - public function dataNotEnumCases() - { - return [ - ['/* testCaseWithSemicolonIsNotEnumCase */'], - ['/* testCaseWithConstantIsNotEnumCase */'], - ['/* testCaseWithConstantAndIdenticalIsNotEnumCase */'], - ['/* testCaseWithAssigmentToConstantIsNotEnumCase */'], - ['/* testIsNotEnumCaseIsCaseInsensitive */'], - ['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'], - ['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'], - ]; - - }//end dataNotEnumCases() - - - /** - * Test that "case" that is not enum case is still tokenized as `T_CASE`. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataKeywordAsEnumCaseNameShouldBeString - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testKeywordAsEnumCaseNameShouldBeString($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]); - - $this->assertSame(T_STRING, $tokens[$enumCaseName]['code']); - $this->assertSame('T_STRING', $tokens[$enumCaseName]['type']); - - }//end testKeywordAsEnumCaseNameShouldBeString() - - - /** - * Data provider. - * - * @see testKeywordAsEnumCaseNameShouldBeString() - * - * @return array - */ - public function dataKeywordAsEnumCaseNameShouldBeString() - { - return [ - ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], - ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], - ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], - ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], - ]; - - }//end dataKeywordAsEnumCaseNameShouldBeString() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php deleted file mode 100644 index 2b28bc5d3..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php +++ /dev/null @@ -1,96 +0,0 @@ - - * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class FinallyTest extends AbstractMethodUnitTest -{ - - - /** - * Test that the finally keyword is tokenized as such. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataFinallyKeyword - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testFinallyKeyword($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); - $this->assertSame(T_FINALLY, $tokens[$target]['code']); - $this->assertSame('T_FINALLY', $tokens[$target]['type']); - - }//end testFinallyKeyword() - - - /** - * Data provider. - * - * @see testFinallyKeyword() - * - * @return array - */ - public function dataFinallyKeyword() - { - return [ - ['/* testTryCatchFinally */'], - ['/* testTryFinallyCatch */'], - ['/* testTryFinally */'], - ]; - - }//end dataFinallyKeyword() - - - /** - * Test that 'finally' when not used as the reserved keyword is tokenized as `T_STRING`. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataFinallyNonKeyword - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testFinallyNonKeyword($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); - - }//end testFinallyNonKeyword() - - - /** - * Data provider. - * - * @see testFinallyNonKeyword() - * - * @return array - */ - public function dataFinallyNonKeyword() - { - return [ - ['/* testFinallyUsedAsClassConstantName */'], - ['/* testFinallyUsedAsMethodName */'], - ['/* testFinallyUsedAsPropertyName */'], - ]; - - }//end dataFinallyNonKeyword() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.inc deleted file mode 100644 index 12df5d296..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.inc +++ /dev/null @@ -1,56 +0,0 @@ - -
- -property: - // Do something. - break; -} - -switch (true) { - /* testNotGotoDeclarationGlobalConstantInTernary */ - case $x === ($cond) ? CONST_A : CONST_B: - // Do something. - break; -} - -/* testNotGotoDeclarationEnumWithType */ -enum Suit: string implements Colorful, CardGame {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.php deleted file mode 100644 index 0f937cc8b..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.php +++ /dev/null @@ -1,175 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class GotoLabelTest extends AbstractMethodUnitTest -{ - - - /** - * Verify that the label in a goto statement is tokenized as T_STRING. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to expect. - * - * @dataProvider dataGotoStatement - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testGotoStatement($testMarker, $testContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $label = $this->getTargetToken($testMarker, T_STRING); - - $this->assertInternalType('int', $label); - $this->assertSame($testContent, $tokens[$label]['content']); - - }//end testGotoStatement() - - - /** - * Data provider. - * - * @see testGotoStatement() - * - * @return array - */ - public function dataGotoStatement() - { - return [ - [ - '/* testGotoStatement */', - 'marker', - ], - [ - '/* testGotoStatementInLoop */', - 'end', - ], - ]; - - }//end dataGotoStatement() - - - /** - * Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to expect. - * - * @dataProvider dataGotoDeclaration - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testGotoDeclaration($testMarker, $testContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $label = $this->getTargetToken($testMarker, T_GOTO_LABEL); - - $this->assertInternalType('int', $label); - $this->assertSame($testContent, $tokens[$label]['content']); - - }//end testGotoDeclaration() - - - /** - * Data provider. - * - * @see testGotoDeclaration() - * - * @return array - */ - public function dataGotoDeclaration() - { - return [ - [ - '/* testGotoDeclaration */', - 'marker:', - ], - [ - '/* testGotoDeclarationOutsideLoop */', - 'end:', - ], - ]; - - }//end dataGotoDeclaration() - - - /** - * Verify that the constant used in a switch - case statement is not confused with a goto label. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $testContent The token content to expect. - * - * @dataProvider dataNotAGotoDeclaration - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testNotAGotoDeclaration($testMarker, $testContent) - { - $tokens = self::$phpcsFile->getTokens(); - $target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent); - - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); - - }//end testNotAGotoDeclaration() - - - /** - * Data provider. - * - * @see testNotAGotoDeclaration() - * - * @return array - */ - public function dataNotAGotoDeclaration() - { - return [ - [ - '/* testNotGotoDeclarationGlobalConstant */', - 'CONSTANT', - ], - [ - '/* testNotGotoDeclarationNamespacedConstant */', - 'CONSTANT', - ], - [ - '/* testNotGotoDeclarationClassConstant */', - 'CONSTANT', - ], - [ - '/* testNotGotoDeclarationClassProperty */', - 'property', - ], - [ - '/* testNotGotoDeclarationGlobalConstantInTernary */', - 'CONST_A', - ], - [ - '/* testNotGotoDeclarationGlobalConstantInTernary */', - 'CONST_B', - ], - [ - '/* testNotGotoDeclarationEnumWithType */', - 'Suit', - ], - ]; - - }//end dataNotAGotoDeclaration() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php deleted file mode 100644 index 6e3224070..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php +++ /dev/null @@ -1,150 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Config; -use PHP_CodeSniffer\Ruleset; -use PHP_CodeSniffer\Files\DummyFile; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -/** - * Heredoc/nowdoc closer token test. - * - * @requires PHP 7.3 - */ -class HeredocNowdocCloserTest extends AbstractMethodUnitTest -{ - - - /** - * Initialize & tokenize \PHP_CodeSniffer\Files\File with code from the test case file. - * - * {@internal This is a near duplicate of the original method. Only difference is that - * tab replacement is enabled for this test.} - * - * @return void - */ - public static function setUpBeforeClass() - { - $config = new Config(); - $config->standards = ['PSR1']; - $config->tabWidth = 4; - - $ruleset = new Ruleset($config); - - // Default to a file with the same name as the test class. Extension is property based. - $relativeCN = str_replace(__NAMESPACE__, '', get_called_class()); - $relativePath = str_replace('\\', DIRECTORY_SEPARATOR, $relativeCN); - $pathToTestFile = realpath(__DIR__).$relativePath.'.'.static::$fileExtension; - - // Make sure the file gets parsed correctly based on the file type. - $contents = 'phpcs_input_file: '.$pathToTestFile.PHP_EOL; - $contents .= file_get_contents($pathToTestFile); - - self::$phpcsFile = new DummyFile($contents, $ruleset, $config); - self::$phpcsFile->process(); - - }//end setUpBeforeClass() - - - /** - * Verify that leading (indent) whitespace in a heredoc/nowdoc closer token get the tab replacement treatment. - * - * @param string $testMarker The comment prefacing the target token. - * @param array $expected Expectations for the token array. - * - * @dataProvider dataHeredocNowdocCloserTabReplacement - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap - * - * @return void - */ - public function testHeredocNowdocCloserTabReplacement($testMarker, $expected) - { - $tokens = self::$phpcsFile->getTokens(); - - $closer = $this->getTargetToken($testMarker, [T_END_HEREDOC, T_END_NOWDOC]); - - foreach ($expected as $key => $value) { - if ($key === 'orig_content' && $value === null) { - $this->assertArrayNotHasKey($key, $tokens[$closer], "Unexpected 'orig_content' key found in the token array."); - continue; - } - - $this->assertArrayHasKey($key, $tokens[$closer], "Key $key not found in the token array."); - $this->assertSame($value, $tokens[$closer][$key], "Value for key $key does not match expectation."); - } - - }//end testHeredocNowdocCloserTabReplacement() - - - /** - * Data provider. - * - * @see testHeredocNowdocCloserTabReplacement() - * - * @return array - */ - public function dataHeredocNowdocCloserTabReplacement() - { - return [ - [ - 'testMarker' => '/* testHeredocCloserNoIndent */', - 'expected' => [ - 'length' => 3, - 'content' => 'EOD', - 'orig_content' => null, - ], - ], - [ - 'testMarker' => '/* testNowdocCloserNoIndent */', - 'expected' => [ - 'length' => 3, - 'content' => 'EOD', - 'orig_content' => null, - ], - ], - [ - 'testMarker' => '/* testHeredocCloserSpaceIndent */', - 'expected' => [ - 'length' => 7, - 'content' => ' END', - 'orig_content' => null, - ], - ], - [ - 'testMarker' => '/* testNowdocCloserSpaceIndent */', - 'expected' => [ - 'length' => 8, - 'content' => ' END', - 'orig_content' => null, - ], - ], - [ - 'testMarker' => '/* testHeredocCloserTabIndent */', - 'expected' => [ - 'length' => 8, - 'content' => ' END', - 'orig_content' => ' END', - ], - ], - [ - 'testMarker' => '/* testNowdocCloserTabIndent */', - 'expected' => [ - 'length' => 7, - 'content' => ' END', - 'orig_content' => ' END', - ], - ], - ]; - - }//end dataHeredocNowdocCloserTabReplacement() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php deleted file mode 100644 index 2c808be90..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php +++ /dev/null @@ -1,153 +0,0 @@ - - * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class HeredocStringTest extends AbstractMethodUnitTest -{ - - - /** - * Test that heredoc strings contain the complete interpolated string. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $expectedContent The expected content of the heredoc string. - * - * @dataProvider dataHeredocString - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testHeredocString($testMarker, $expectedContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, T_HEREDOC); - $this->assertSame($expectedContent."\n", $tokens[$target]['content']); - - }//end testHeredocString() - - - /** - * Test that heredoc strings contain the complete interpolated string when combined with other texts. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $expectedContent The expected content of the heredoc string. - * - * @dataProvider dataHeredocString - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testHeredocStringWrapped($testMarker, $expectedContent) - { - $tokens = self::$phpcsFile->getTokens(); - - $testMarker = substr($testMarker, 0, -3).'Wrapped */'; - $target = $this->getTargetToken($testMarker, T_HEREDOC); - $this->assertSame('Do '.$expectedContent." Something\n", $tokens[$target]['content']); - - }//end testHeredocStringWrapped() - - - /** - * Data provider. - * - * @see testHeredocString() - * - * @return array - */ - public function dataHeredocString() - { - return [ - [ - 'testMarker' => '/* testSimple1 */', - 'expectedContent' => '$foo', - ], - [ - 'testMarker' => '/* testSimple2 */', - 'expectedContent' => '{$foo}', - ], - [ - 'testMarker' => '/* testSimple3 */', - 'expectedContent' => '${foo}', - ], - [ - 'testMarker' => '/* testDIM1 */', - 'expectedContent' => '$foo[bar]', - ], - [ - 'testMarker' => '/* testDIM2 */', - 'expectedContent' => '{$foo[\'bar\']}', - ], - [ - 'testMarker' => '/* testDIM3 */', - 'expectedContent' => '${foo[\'bar\']}', - ], - [ - 'testMarker' => '/* testProperty1 */', - 'expectedContent' => '$foo->bar', - ], - [ - 'testMarker' => '/* testProperty2 */', - 'expectedContent' => '{$foo->bar}', - ], - [ - 'testMarker' => '/* testMethod1 */', - 'expectedContent' => '{$foo->bar()}', - ], - [ - 'testMarker' => '/* testClosure1 */', - 'expectedContent' => '{$foo()}', - ], - [ - 'testMarker' => '/* testChain1 */', - 'expectedContent' => '{$foo[\'bar\']->baz()()}', - ], - [ - 'testMarker' => '/* testVariableVar1 */', - 'expectedContent' => '${$bar}', - ], - [ - 'testMarker' => '/* testVariableVar2 */', - 'expectedContent' => '${(foo)}', - ], - [ - 'testMarker' => '/* testVariableVar3 */', - 'expectedContent' => '${foo->bar}', - ], - [ - 'testMarker' => '/* testNested1 */', - 'expectedContent' => '${foo["${bar}"]}', - ], - [ - 'testMarker' => '/* testNested2 */', - 'expectedContent' => '${foo["${bar[\'baz\']}"]}', - ], - [ - 'testMarker' => '/* testNested3 */', - 'expectedContent' => '${foo->{$baz}}', - ], - [ - 'testMarker' => '/* testNested4 */', - 'expectedContent' => '${foo->{${\'a\'}}}', - ], - [ - 'testMarker' => '/* testNested5 */', - 'expectedContent' => '${foo->{"${\'a\'}"}}', - ], - ]; - - }//end dataHeredocString() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php deleted file mode 100644 index cc57637c6..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php +++ /dev/null @@ -1,885 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -use PHP_CodeSniffer\Util\Tokens; - -class NamedFunctionCallArgumentsTest extends AbstractMethodUnitTest -{ - - - /** - * Verify that parameter labels are tokenized as T_PARAM_NAME and that - * the colon after it is tokenized as a T_COLON. - * - * @param string $testMarker The comment prefacing the target token. - * @param array $parameters The token content for each parameter label to look for. - * - * @dataProvider dataNamedFunctionCallArguments - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testNamedFunctionCallArguments($testMarker, $parameters) - { - $tokens = self::$phpcsFile->getTokens(); - - foreach ($parameters as $content) { - $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); - - $this->assertSame( - T_PARAM_NAME, - $tokens[$label]['code'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)' - ); - $this->assertSame( - 'T_PARAM_NAME', - $tokens[$label]['type'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)' - ); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - }//end foreach - - }//end testNamedFunctionCallArguments() - - - /** - * Data provider. - * - * @see testNamedFunctionCallArguments() - * - * @return array - */ - public function dataNamedFunctionCallArguments() - { - return [ - [ - '/* testNamedArgs */', - [ - 'start_index', - 'count', - 'value', - ], - ], - [ - '/* testNamedArgsMultiline */', - [ - 'start_index', - 'count', - 'value', - ], - ], - [ - '/* testNamedArgsWithWhitespaceAndComments */', - [ - 'start_index', - 'count', - 'value', - ], - ], - [ - '/* testMixedPositionalAndNamedArgs */', - ['double_encode'], - ], - [ - '/* testNestedFunctionCallOuter */', - [ - 'start_index', - 'count', - 'value', - ], - ], - [ - '/* testNestedFunctionCallInner1 */', - ['skip'], - ], - [ - '/* testNestedFunctionCallInner2 */', - ['array_or_countable'], - ], - [ - '/* testNamespaceOperatorFunction */', - [ - 'label', - 'more', - ], - ], - [ - '/* testNamespaceRelativeFunction */', - [ - 'label', - 'more', - ], - ], - [ - '/* testNamespacedFQNFunction */', - [ - 'label', - 'more', - ], - ], - [ - '/* testVariableFunction */', - [ - 'label', - 'more', - ], - ], - [ - '/* testVariableVariableFunction */', - [ - 'label', - 'more', - ], - ], - [ - '/* testMethodCall */', - [ - 'label', - 'more', - ], - ], - [ - '/* testVariableMethodCall */', - [ - 'label', - 'more', - ], - ], - [ - '/* testClassInstantiation */', - [ - 'label', - 'more', - ], - ], - [ - '/* testClassInstantiationSelf */', - [ - 'label', - 'more', - ], - ], - [ - '/* testClassInstantiationStatic */', - [ - 'label', - 'more', - ], - ], - [ - '/* testAnonClass */', - [ - 'label', - 'more', - ], - ], - [ - '/* testNonAsciiNames */', - [ - '💩💩💩', - 'Пасха', - '_valid', - ], - ], - - // Coding errors which should still be handled. - [ - '/* testCompileErrorNamedBeforePositional */', - ['param'], - ], - [ - '/* testDuplicateName1 */', - ['param'], - ], - [ - '/* testDuplicateName2 */', - ['param'], - ], - [ - '/* testIncorrectOrderWithVariadic */', - ['start_index'], - ], - [ - '/* testCompileErrorIncorrectOrderWithVariadic */', - ['param'], - ], - [ - '/* testParseErrorNoValue */', - [ - 'param1', - 'param2', - ], - ], - [ - '/* testParseErrorExit */', - ['status'], - ], - [ - '/* testParseErrorEmpty */', - ['variable'], - ], - [ - '/* testParseErrorEval */', - ['code'], - ], - [ - '/* testParseErrorArbitraryParentheses */', - ['something'], - ], - ]; - - }//end dataNamedFunctionCallArguments() - - - /** - * Verify that other T_STRING tokens within a function call are still tokenized as T_STRING. - * - * @param string $testMarker The comment prefacing the target token. - * @param string $content The token content to look for. - * - * @dataProvider dataOtherTstringInFunctionCall - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testOtherTstringInFunctionCall($testMarker, $content) - { - $tokens = self::$phpcsFile->getTokens(); - - $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); - - $this->assertSame( - T_STRING, - $tokens[$label]['code'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (code)' - ); - $this->assertSame( - 'T_STRING', - $tokens[$label]['type'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (type)' - ); - - }//end testOtherTstringInFunctionCall() - - - /** - * Data provider. - * - * @see testOtherTstringInFunctionCall() - * - * @return array - */ - public function dataOtherTstringInFunctionCall() - { - return [ - [ - '/* testPositionalArgs */', - 'START_INDEX', - ], - [ - '/* testPositionalArgs */', - 'COUNT', - ], - [ - '/* testPositionalArgs */', - 'VALUE', - ], - [ - '/* testNestedFunctionCallInner2 */', - 'count', - ], - ]; - - }//end dataOtherTstringInFunctionCall() - - - /** - * Verify whether the colons are tokenized correctly when a ternary is used in a mixed - * positional and named arguments function call. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testMixedPositionalAndNamedArgsWithTernary() - { - $tokens = self::$phpcsFile->getTokens(); - - $true = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_TRUE); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); - - $this->assertSame( - T_INLINE_ELSE, - $tokens[$colon]['code'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' - ); - $this->assertSame( - 'T_INLINE_ELSE', - $tokens[$colon]['type'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' - ); - - $label = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_PARAM_NAME, 'name'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - }//end testMixedPositionalAndNamedArgsWithTernary() - - - /** - * Verify whether the colons are tokenized correctly when a ternary is used - * in a named arguments function call. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testNamedArgWithTernary() - { - $tokens = self::$phpcsFile->getTokens(); - - /* - * First argument. - */ - - $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'label'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'First arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_TRUE); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); - - $this->assertSame( - T_INLINE_ELSE, - $tokens[$colon]['code'], - 'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' - ); - $this->assertSame( - 'T_INLINE_ELSE', - $tokens[$colon]['type'], - 'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' - ); - - /* - * Second argument. - */ - - $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'more'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'Second arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_STRING, 'CONSTANT_A'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); - - $this->assertSame( - T_INLINE_ELSE, - $tokens[$colon]['code'], - 'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' - ); - $this->assertSame( - 'T_INLINE_ELSE', - $tokens[$colon]['type'], - 'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' - ); - - }//end testNamedArgWithTernary() - - - /** - * Verify whether the colons are tokenized correctly when named arguments - * function calls are used in a ternary. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testTernaryWithFunctionCallsInThenElse() - { - $tokens = self::$phpcsFile->getTokens(); - - /* - * Then. - */ - - $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'label'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'Function in then: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - $closeParens = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_CLOSE_PARENTHESIS); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($closeParens + 1), null, true); - - $this->assertSame( - T_INLINE_ELSE, - $tokens[$colon]['code'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' - ); - $this->assertSame( - 'T_INLINE_ELSE', - $tokens[$colon]['type'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' - ); - - /* - * Else. - */ - - $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'more'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'Function in else: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - }//end testTernaryWithFunctionCallsInThenElse() - - - /** - * Verify whether the colons are tokenized correctly when constants are used in a ternary. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testTernaryWithConstantsInThenElse() - { - $tokens = self::$phpcsFile->getTokens(); - - $constant = $this->getTargetToken('/* testTernaryWithConstantsInThenElse */', T_STRING, 'CONSTANT_NAME'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($constant + 1), null, true); - - $this->assertSame( - T_INLINE_ELSE, - $tokens[$colon]['code'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' - ); - $this->assertSame( - 'T_INLINE_ELSE', - $tokens[$colon]['type'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' - ); - - }//end testTernaryWithConstantsInThenElse() - - - /** - * Verify whether the colons are tokenized correctly in a switch statement. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testSwitchStatement() - { - $tokens = self::$phpcsFile->getTokens(); - - $label = $this->getTargetToken('/* testSwitchCaseWithConstant */', T_STRING, 'MY_CONSTANT'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - $label = $this->getTargetToken('/* testSwitchCaseWithClassProperty */', T_STRING, 'property'); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - $default = $this->getTargetToken('/* testSwitchDefault */', T_DEFAULT); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($default + 1), null, true); - - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - }//end testSwitchStatement() - - - /** - * Verify that a variable parameter label (parse error) is still tokenized as T_VARIABLE. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testParseErrorVariableLabel() - { - $tokens = self::$phpcsFile->getTokens(); - - $label = $this->getTargetToken('/* testParseErrorDynamicName */', [T_VARIABLE, T_PARAM_NAME], '$variableStoringParamName'); - - $this->assertSame( - T_VARIABLE, - $tokens[$label]['code'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (code)' - ); - $this->assertSame( - 'T_VARIABLE', - $tokens[$label]['type'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (type)' - ); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - }//end testParseErrorVariableLabel() - - - /** - * Verify that reserved keywords used as a parameter label are tokenized as T_PARAM_NAME - * and that the colon after it is tokenized as a T_COLON. - * - * @param string $testMarker The comment prefacing the target token. - * @param array $tokenTypes The token codes to look for. - * @param string $tokenContent The token content to look for. - * - * @dataProvider dataReservedKeywordsAsName - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testReservedKeywordsAsName($testMarker, $tokenTypes, $tokenContent) - { - $tokens = self::$phpcsFile->getTokens(); - $label = $this->getTargetToken($testMarker, $tokenTypes, $tokenContent); - - $this->assertSame( - T_PARAM_NAME, - $tokens[$label]['code'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)' - ); - $this->assertSame( - 'T_PARAM_NAME', - $tokens[$label]['type'], - 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)' - ); - - // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); - - $this->assertSame( - ':', - $tokens[$colon]['content'], - 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] - ); - $this->assertSame( - T_COLON, - $tokens[$colon]['code'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' - ); - $this->assertSame( - 'T_COLON', - $tokens[$colon]['type'], - 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' - ); - - }//end testReservedKeywordsAsName() - - - /** - * Data provider. - * - * @see testReservedKeywordsAsName() - * - * @return array - */ - public function dataReservedKeywordsAsName() - { - $reservedKeywords = [ - // '__halt_compiler', NOT TESTABLE - 'abstract', - 'and', - 'array', - 'as', - 'break', - 'callable', - 'case', - 'catch', - 'class', - 'clone', - 'const', - 'continue', - 'declare', - 'default', - 'die', - 'do', - 'echo', - 'else', - 'elseif', - 'empty', - 'enddeclare', - 'endfor', - 'endforeach', - 'endif', - 'endswitch', - 'endwhile', - 'enum', - 'eval', - 'exit', - 'extends', - 'final', - 'finally', - 'fn', - 'for', - 'foreach', - 'function', - 'global', - 'goto', - 'if', - 'implements', - 'include', - 'include_once', - 'instanceof', - 'insteadof', - 'interface', - 'isset', - 'list', - 'match', - 'namespace', - 'new', - 'or', - 'print', - 'private', - 'protected', - 'public', - 'readonly', - 'require', - 'require_once', - 'return', - 'static', - 'switch', - 'throw', - 'trait', - 'try', - 'unset', - 'use', - 'var', - 'while', - 'xor', - 'yield', - 'int', - 'float', - 'bool', - 'string', - 'true', - 'false', - 'null', - 'void', - 'iterable', - 'object', - 'resource', - 'mixed', - 'numeric', - 'never', - - // Not reserved keyword, but do have their own token in PHPCS. - 'parent', - 'self', - ]; - - $data = []; - - foreach ($reservedKeywords as $keyword) { - $tokensTypes = [ - T_PARAM_NAME, - T_STRING, - T_GOTO_LABEL, - ]; - $tokenName = 'T_'.strtoupper($keyword); - - if ($keyword === 'and') { - $tokensTypes[] = T_LOGICAL_AND; - } else if ($keyword === 'die') { - $tokensTypes[] = T_EXIT; - } else if ($keyword === 'or') { - $tokensTypes[] = T_LOGICAL_OR; - } else if ($keyword === 'xor') { - $tokensTypes[] = T_LOGICAL_XOR; - } else if ($keyword === '__halt_compiler') { - $tokensTypes[] = T_HALT_COMPILER; - } else if (defined($tokenName) === true) { - $tokensTypes[] = constant($tokenName); - } - - $data[$keyword.'FirstParam'] = [ - '/* testReservedKeyword'.ucfirst($keyword).'1 */', - $tokensTypes, - $keyword, - ]; - - $data[$keyword.'SecondParam'] = [ - '/* testReservedKeyword'.ucfirst($keyword).'2 */', - $tokensTypes, - $keyword, - ]; - }//end foreach - - return $data; - - }//end dataReservedKeywordsAsName() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php deleted file mode 100644 index 8e465a3be..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php +++ /dev/null @@ -1,140 +0,0 @@ -= 8.0 nullsafe object operator. - * - * @author Juliette Reinders Folmer - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -use PHP_CodeSniffer\Util\Tokens; - -class NullsafeObjectOperatorTest extends AbstractMethodUnitTest -{ - - /** - * Tokens to search for. - * - * @var array - */ - protected $find = [ - T_NULLSAFE_OBJECT_OPERATOR, - T_OBJECT_OPERATOR, - T_INLINE_THEN, - ]; - - - /** - * Test that a normal object operator is still tokenized as such. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testObjectOperator() - { - $tokens = self::$phpcsFile->getTokens(); - - $operator = $this->getTargetToken('/* testObjectOperator */', $this->find); - $this->assertSame(T_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is object operator'); - $this->assertSame('T_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is object operator'); - - }//end testObjectOperator() - - - /** - * Test that a nullsafe object operator is tokenized as such. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataNullsafeObjectOperator - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testNullsafeObjectOperator($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $operator = $this->getTargetToken($testMarker, $this->find); - $this->assertSame(T_NULLSAFE_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is nullsafe object operator'); - $this->assertSame('T_NULLSAFE_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is nullsafe object operator'); - - }//end testNullsafeObjectOperator() - - - /** - * Data provider. - * - * @see testNullsafeObjectOperator() - * - * @return array - */ - public function dataNullsafeObjectOperator() - { - return [ - ['/* testNullsafeObjectOperator */'], - ['/* testNullsafeObjectOperatorWriteContext */'], - ]; - - }//end dataNullsafeObjectOperator() - - - /** - * Test that a question mark not followed by an object operator is tokenized as T_TERNARY_THEN. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param bool $testObjectOperator Whether to test for the next non-empty token being tokenized - * as an object operator. - * - * @dataProvider dataTernaryThen - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testTernaryThen($testMarker, $testObjectOperator=false) - { - $tokens = self::$phpcsFile->getTokens(); - - $operator = $this->getTargetToken($testMarker, $this->find); - $this->assertSame(T_INLINE_THEN, $tokens[$operator]['code'], 'Failed asserting code is inline then'); - $this->assertSame('T_INLINE_THEN', $tokens[$operator]['type'], 'Failed asserting type is inline then'); - - if ($testObjectOperator === true) { - $next = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($operator + 1), null, true); - $this->assertSame(T_OBJECT_OPERATOR, $tokens[$next]['code'], 'Failed asserting code is object operator'); - $this->assertSame('T_OBJECT_OPERATOR', $tokens[$next]['type'], 'Failed asserting type is object operator'); - } - - }//end testTernaryThen() - - - /** - * Data provider. - * - * @see testTernaryThen() - * - * @return array - */ - public function dataTernaryThen() - { - return [ - ['/* testTernaryThen */'], - [ - '/* testParseErrorWhitespaceNotAllowed */', - true, - ], - [ - '/* testParseErrorCommentNotAllowed */', - true, - ], - ['/* testLiveCoding */'], - ]; - - }//end dataTernaryThen() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php deleted file mode 100644 index 23cbd9877..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php +++ /dev/null @@ -1,98 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class ScopeSettingWithNamespaceOperatorTest extends AbstractMethodUnitTest -{ - - - /** - * Test that the scope opener/closers are set correctly when the namespace keyword is encountered as an operator. - * - * @param string $testMarker The comment which prefaces the target tokens in the test file. - * @param int|string[] $tokenTypes The token type to search for. - * @param int|string[] $open Optional. The token type for the scope opener. - * @param int|string[] $close Optional. The token type for the scope closer. - * - * @dataProvider dataScopeSetting - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap - * - * @return void - */ - public function testScopeSetting($testMarker, $tokenTypes, $open=T_OPEN_CURLY_BRACKET, $close=T_CLOSE_CURLY_BRACKET) - { - $tokens = self::$phpcsFile->getTokens(); - - $target = $this->getTargetToken($testMarker, $tokenTypes); - $opener = $this->getTargetToken($testMarker, $open); - $closer = $this->getTargetToken($testMarker, $close); - - $this->assertArrayHasKey('scope_opener', $tokens[$target], 'Scope opener missing'); - $this->assertArrayHasKey('scope_closer', $tokens[$target], 'Scope closer missing'); - $this->assertSame($opener, $tokens[$target]['scope_opener'], 'Scope opener not same'); - $this->assertSame($closer, $tokens[$target]['scope_closer'], 'Scope closer not same'); - - $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Scope opener missing for open curly'); - $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Scope closer missing for open curly'); - $this->assertSame($opener, $tokens[$opener]['scope_opener'], 'Scope opener not same for open curly'); - $this->assertSame($closer, $tokens[$opener]['scope_closer'], 'Scope closer not same for open curly'); - - $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Scope opener missing for close curly'); - $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Scope closer missing for close curly'); - $this->assertSame($opener, $tokens[$closer]['scope_opener'], 'Scope opener not same for close curly'); - $this->assertSame($closer, $tokens[$closer]['scope_closer'], 'Scope closer not same for close curly'); - - }//end testScopeSetting() - - - /** - * Data provider. - * - * @see testScopeSetting() - * - * @return array - */ - public function dataScopeSetting() - { - return [ - [ - '/* testClassExtends */', - [T_CLASS], - ], - [ - '/* testClassImplements */', - [T_ANON_CLASS], - ], - [ - '/* testInterfaceExtends */', - [T_INTERFACE], - ], - [ - '/* testFunctionReturnType */', - [T_FUNCTION], - ], - [ - '/* testClosureReturnType */', - [T_CLOSURE], - ], - [ - '/* testArrowFunctionReturnType */', - [T_FN], - [T_FN_ARROW], - [T_SEMICOLON], - ], - ]; - - }//end dataScopeSetting() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php deleted file mode 100644 index 1d97894f5..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php +++ /dev/null @@ -1,135 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class ShortArrayTest extends AbstractMethodUnitTest -{ - - - /** - * Test that real square brackets are still tokenized as square brackets. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataSquareBrackets - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testSquareBrackets($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); - $this->assertSame(T_OPEN_SQUARE_BRACKET, $tokens[$opener]['code']); - $this->assertSame('T_OPEN_SQUARE_BRACKET', $tokens[$opener]['type']); - - if (isset($tokens[$opener]['bracket_closer']) === true) { - $closer = $tokens[$opener]['bracket_closer']; - $this->assertSame(T_CLOSE_SQUARE_BRACKET, $tokens[$closer]['code']); - $this->assertSame('T_CLOSE_SQUARE_BRACKET', $tokens[$closer]['type']); - } - - }//end testSquareBrackets() - - - /** - * Data provider. - * - * @see testSquareBrackets() - * - * @return array - */ - public function dataSquareBrackets() - { - return [ - 'array access 1' => ['/* testArrayAccess1 */'], - 'array access 2' => ['/* testArrayAccess2 */'], - 'array assignment' => ['/* testArrayAssignment */'], - 'function call dereferencing' => ['/* testFunctionCallDereferencing */'], - 'method call dereferencing' => ['/* testMethodCallDereferencing */'], - 'static method call dereferencing' => ['/* testStaticMethodCallDereferencing */'], - 'property dereferencing' => ['/* testPropertyDereferencing */'], - 'property dereferencing with inaccessable name' => ['/* testPropertyDereferencingWithInaccessibleName */'], - 'static property dereferencing' => ['/* testStaticPropertyDereferencing */'], - 'string dereferencing single quotes' => ['/* testStringDereferencing */'], - 'string dereferencing double quotes' => ['/* testStringDereferencingDoubleQuoted */'], - 'global constant dereferencing' => ['/* testConstantDereferencing */'], - 'class constant dereferencing' => ['/* testClassConstantDereferencing */'], - 'magic constant dereferencing' => ['/* testMagicConstantDereferencing */'], - 'array access with curly braces' => ['/* testArrayAccessCurlyBraces */'], - 'array literal dereferencing' => ['/* testArrayLiteralDereferencing */'], - 'short array literal dereferencing' => ['/* testShortArrayLiteralDereferencing */'], - 'class member dereferencing on instantiation 1' => ['/* testClassMemberDereferencingOnInstantiation1 */'], - 'class member dereferencing on instantiation 2' => ['/* testClassMemberDereferencingOnInstantiation2 */'], - 'class member dereferencing on clone' => ['/* testClassMemberDereferencingOnClone */'], - 'nullsafe method call dereferencing' => ['/* testNullsafeMethodCallDereferencing */'], - 'interpolated string dereferencing' => ['/* testInterpolatedStringDereferencing */'], - 'live coding' => ['/* testLiveCoding */'], - ]; - - }//end dataSquareBrackets() - - - /** - * Test that short arrays and short lists are still tokenized as short arrays. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataShortArrays - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testShortArrays($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); - $this->assertSame(T_OPEN_SHORT_ARRAY, $tokens[$opener]['code']); - $this->assertSame('T_OPEN_SHORT_ARRAY', $tokens[$opener]['type']); - - if (isset($tokens[$opener]['bracket_closer']) === true) { - $closer = $tokens[$opener]['bracket_closer']; - $this->assertSame(T_CLOSE_SHORT_ARRAY, $tokens[$closer]['code']); - $this->assertSame('T_CLOSE_SHORT_ARRAY', $tokens[$closer]['type']); - } - - }//end testShortArrays() - - - /** - * Data provider. - * - * @see testShortArrays() - * - * @return array - */ - public function dataShortArrays() - { - return [ - 'short array empty' => ['/* testShortArrayDeclarationEmpty */'], - 'short array with value' => ['/* testShortArrayDeclarationWithOneValue */'], - 'short array with values' => ['/* testShortArrayDeclarationWithMultipleValues */'], - 'short array with dereferencing' => ['/* testShortArrayDeclarationWithDereferencing */'], - 'short list' => ['/* testShortListDeclaration */'], - 'short list nested' => ['/* testNestedListDeclaration */'], - 'short array within function call' => ['/* testArrayWithinFunctionCall */'], - 'short list after braced control structure' => ['/* testShortListDeclarationAfterBracedControlStructure */'], - 'short list after non-braced control structure' => ['/* testShortListDeclarationAfterNonBracedControlStructure */'], - 'short list after alternative control structure' => ['/* testShortListDeclarationAfterAlternativeControlStructure */'], - ]; - - }//end dataShortArrays() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php deleted file mode 100644 index d2ab47cac..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php +++ /dev/null @@ -1,367 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -use PHP_CodeSniffer\Util\Tokens; - -class StableCommentWhitespaceWinTest extends AbstractMethodUnitTest -{ - - - /** - * Test that comment tokenization with new lines at the end of the comment is stable. - * - * @param string $testMarker The comment prefacing the test. - * @param array $expectedTokens The tokenization expected. - * - * @dataProvider dataCommentTokenization - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * - * @return void - */ - public function testCommentTokenization($testMarker, $expectedTokens) - { - $tokens = self::$phpcsFile->getTokens(); - $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); - - foreach ($expectedTokens as $key => $tokenInfo) { - $this->assertSame(constant($tokenInfo['type']), $tokens[$comment]['code']); - $this->assertSame($tokenInfo['type'], $tokens[$comment]['type']); - $this->assertSame($tokenInfo['content'], $tokens[$comment]['content']); - - ++$comment; - } - - }//end testCommentTokenization() - - - /** - * Data provider. - * - * @see testCommentTokenization() - * - * @return array - */ - public function dataCommentTokenization() - { - return [ - [ - '/* testSingleLineSlashComment */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testSingleLineSlashCommentTrailing */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testSingleLineSlashAnnotation */', - [ - [ - 'type' => 'T_PHPCS_DISABLE', - 'content' => '// phpcs:disable Stnd.Cat -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testMultiLineSlashComment */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment1 -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment2 -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment3 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testMultiLineSlashCommentWithIndent */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment1 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' ', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment2 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' ', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment3 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testMultiLineSlashCommentWithAnnotationStart */', - [ - [ - 'type' => 'T_PHPCS_IGNORE', - 'content' => '// phpcs:ignore Stnd.Cat -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment2 -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment3 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testMultiLineSlashCommentWithAnnotationMiddle */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment1 -', - ], - [ - 'type' => 'T_PHPCS_IGNORE', - 'content' => '// @phpcs:ignore Stnd.Cat -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment3 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testMultiLineSlashCommentWithAnnotationEnd */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment1 -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '// Comment2 -', - ], - [ - 'type' => 'T_PHPCS_IGNORE', - 'content' => '// phpcs:ignore Stnd.Cat -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testSingleLineSlashCommentNoNewLineAtEnd */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '// Slash ', - ], - [ - 'type' => 'T_CLOSE_TAG', - 'content' => '?> -', - ], - ], - ], - [ - '/* testSingleLineHashComment */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testSingleLineHashCommentTrailing */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testMultiLineHashComment */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment1 -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment2 -', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment3 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testMultiLineHashCommentWithIndent */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment1 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' ', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment2 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' ', - ], - [ - 'type' => 'T_COMMENT', - 'content' => '# Comment3 -', - ], - [ - 'type' => 'T_WHITESPACE', - 'content' => ' -', - ], - ], - ], - [ - '/* testSingleLineHashCommentNoNewLineAtEnd */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '# Hash ', - ], - [ - 'type' => 'T_CLOSE_TAG', - 'content' => '?> -', - ], - ], - ], - [ - '/* testCommentAtEndOfFile */', - [ - [ - 'type' => 'T_COMMENT', - 'content' => '/* Comment', - ], - ], - ], - ]; - - }//end dataCommentTokenization() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc deleted file mode 100644 index abf9b85ba..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc +++ /dev/null @@ -1,120 +0,0 @@ - $param & $int; - -/* testTypeIntersectionArrowReturnType */ -$arrowWithReturnType = fn ($param) : Foo&Bar => $param * 10; - -/* testBitwiseAndInArrayKey */ -$array = array( - A & B => /* testBitwiseAndInArrayValue */ B & C -); - -/* testBitwiseAndInShortArrayKey */ -$array = [ - A & B => /* testBitwiseAndInShortArrayValue */ B & C -]; - -/* testBitwiseAndNonArrowFnFunctionCall */ -$obj->fn($something & $else); - -/* testBitwiseAnd6 */ -function &fn(/* testTypeIntersectionNonArrowFunctionDeclaration */ Foo&Bar $something) {} - -/* testTypeIntersectionWithInvalidTypes */ -function (int&string $var) {}; - -/* testLiveCoding */ -// Intentional parse error. This has to be the last test in the file. -return function( Foo& diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php deleted file mode 100644 index 217002193..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php +++ /dev/null @@ -1,138 +0,0 @@ - - * @author Jaroslav Hanslík - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class TypeIntersectionTest extends AbstractMethodUnitTest -{ - - - /** - * Test that non-intersection type bitwise and tokens are still tokenized as bitwise and. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataBitwiseAnd - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testBitwiseAnd($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $opener = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); - $this->assertSame(T_BITWISE_AND, $tokens[$opener]['code']); - $this->assertSame('T_BITWISE_AND', $tokens[$opener]['type']); - - }//end testBitwiseAnd() - - - /** - * Data provider. - * - * @see testBitwiseAnd() - * - * @return array - */ - public function dataBitwiseAnd() - { - return [ - ['/* testBitwiseAnd1 */'], - ['/* testBitwiseAnd2 */'], - ['/* testBitwiseAndPropertyDefaultValue */'], - ['/* testBitwiseAndParamDefaultValue */'], - ['/* testBitwiseAnd3 */'], - ['/* testBitwiseAnd4 */'], - ['/* testBitwiseAnd5 */'], - ['/* testBitwiseAndClosureParamDefault */'], - ['/* testBitwiseAndArrowParamDefault */'], - ['/* testBitwiseAndArrowExpression */'], - ['/* testBitwiseAndInArrayKey */'], - ['/* testBitwiseAndInArrayValue */'], - ['/* testBitwiseAndInShortArrayKey */'], - ['/* testBitwiseAndInShortArrayValue */'], - ['/* testBitwiseAndNonArrowFnFunctionCall */'], - ['/* testBitwiseAnd6 */'], - ['/* testLiveCoding */'], - ]; - - }//end dataBitwiseAnd() - - - /** - * Test that bitwise and tokens when used as part of a intersection type are tokenized as `T_TYPE_INTERSECTION`. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataTypeIntersection - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional - * - * @return void - */ - public function testTypeIntersection($testMarker) - { - $tokens = self::$phpcsFile->getTokens(); - - $opener = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); - $this->assertSame(T_TYPE_INTERSECTION, $tokens[$opener]['code']); - $this->assertSame('T_TYPE_INTERSECTION', $tokens[$opener]['type']); - - }//end testTypeIntersection() - - - /** - * Data provider. - * - * @see testTypeIntersection() - * - * @return array - */ - public function dataTypeIntersection() - { - return [ - ['/* testTypeIntersectionPropertySimple */'], - ['/* testTypeIntersectionPropertyReverseModifierOrder */'], - ['/* testTypeIntersectionPropertyMulti1 */'], - ['/* testTypeIntersectionPropertyMulti2 */'], - ['/* testTypeIntersectionPropertyMulti3 */'], - ['/* testTypeIntersectionPropertyNamespaceRelative */'], - ['/* testTypeIntersectionPropertyPartiallyQualified */'], - ['/* testTypeIntersectionPropertyFullyQualified */'], - ['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'], - ['/* testTypeIntersectionParam1 */'], - ['/* testTypeIntersectionParam2 */'], - ['/* testTypeIntersectionParam3 */'], - ['/* testTypeIntersectionParamNamespaceRelative */'], - ['/* testTypeIntersectionParamPartiallyQualified */'], - ['/* testTypeIntersectionParamFullyQualified */'], - ['/* testTypeIntersectionReturnType */'], - ['/* testTypeIntersectionConstructorPropertyPromotion */'], - ['/* testTypeIntersectionAbstractMethodReturnType1 */'], - ['/* testTypeIntersectionAbstractMethodReturnType2 */'], - ['/* testTypeIntersectionReturnTypeNamespaceRelative */'], - ['/* testTypeIntersectionReturnPartiallyQualified */'], - ['/* testTypeIntersectionReturnFullyQualified */'], - ['/* testTypeIntersectionClosureParamIllegalNullable */'], - ['/* testTypeIntersectionWithReference */'], - ['/* testTypeIntersectionWithSpreadOperator */'], - ['/* testTypeIntersectionClosureReturn */'], - ['/* testTypeIntersectionArrowParam */'], - ['/* testTypeIntersectionArrowReturnType */'], - ['/* testTypeIntersectionNonArrowFunctionDeclaration */'], - ['/* testTypeIntersectionWithInvalidTypes */'], - ]; - - }//end dataTypeIntersection() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php new file mode 100644 index 000000000..f3daf2bf2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php @@ -0,0 +1,147 @@ + + * @copyright 2018-2019 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers; + +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHPUnit\Framework\TestCase; +use ReflectionProperty; + +abstract class AbstractTokenizerTestCase extends TestCase +{ + + /** + * The file extension of the test case file (without leading dot). + * + * This allows child classes to overrule the default `inc` with, for instance, + * `js` or `css` when applicable. + * + * @var string + */ + protected $fileExtension = 'inc'; + + /** + * The tab width setting to use when tokenizing the file. + * + * This allows for test case files to use a different tab width than the default. + * + * @var integer + */ + protected $tabWidth = 4; + + /** + * The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file. + * + * @var \PHP_CodeSniffer\Files\File + */ + protected $phpcsFile; + + + /** + * Initialize & tokenize \PHP_CodeSniffer\Files\File with code from the test case file. + * + * The test case file for a unit test class has to be in the same directory + * directory and use the same file name as the test class, using the .inc extension. + * + * @before + * + * @return void + */ + protected function initializeFile() + { + if (isset($this->phpcsFile) === false) { + $_SERVER['argv'] = []; + $config = new ConfigDouble(); + + // Also set a tab-width to enable testing tab-replaced vs `orig_content`. + $config->tabWidth = $this->tabWidth; + + $ruleset = new Ruleset($config); + + // Default to a file with the same name as the test class. Extension is property based. + $relativeCN = str_replace(__NAMESPACE__, '', get_called_class()); + $relativePath = str_replace('\\', DIRECTORY_SEPARATOR, $relativeCN); + $pathToTestFile = realpath(__DIR__).$relativePath.'.'.$this->fileExtension; + + // Make sure the file gets parsed correctly based on the file type. + $contents = 'phpcs_input_file: '.$pathToTestFile.PHP_EOL; + $contents .= file_get_contents($pathToTestFile); + + $this->phpcsFile = new DummyFile($contents, $ruleset, $config); + $this->phpcsFile->parse(); + }//end if + + }//end initializeFile() + + + /** + * Test QA: verify that a test case file does not contain any duplicate test markers. + * + * When a test case file contains a lot of test cases, it is easy to overlook that a test marker name + * is already in use. + * A test wouldn't necessarily fail on this, but would not be testing what is intended to be tested as + * it would be verifying token properties for the wrong token. + * + * This test safeguards against this. + * + * @coversNothing + * + * @return void + */ + public function testTestMarkersAreUnique() + { + AbstractMethodUnitTest::assertTestMarkersAreUnique($this->phpcsFile); + + }//end testTestMarkersAreUnique() + + + /** + * Get the token pointer for a target token based on a specific comment found on the line before. + * + * Note: the test delimiter comment MUST start with "/* test" to allow this function to + * distinguish between comments used *in* a test and test delimiters. + * + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. + * + * @return int + */ + protected function getTargetToken($commentString, $tokenType, $tokenContent=null) + { + return AbstractMethodUnitTest::getTargetTokenFromFile($this->phpcsFile, $commentString, $tokenType, $tokenContent); + + }//end getTargetToken() + + + /** + * Clear the static "resolved tokens" cache property on the Tokenizer\PHP class. + * + * This method should be used selectively by tests to ensure the code under test is actually hit + * by the test testing the code. + * + * @return void + */ + public static function clearResolvedTokensCache() + { + $property = new ReflectionProperty('PHP_CodeSniffer\Tokenizers\PHP', 'resolveTokenCache'); + $property->setAccessible(true); + $property->setValue(null, []); + $property->setAccessible(false); + + }//end clearResolvedTokensCache() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php new file mode 100644 index 000000000..625029db1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php @@ -0,0 +1,117 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Base class for testing DocBlock comment tokenization. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +abstract class CommentTestCase extends AbstractTokenizerTestCase +{ + + + /** + * Test whether the docblock opener and closer have the expected extra keys. + * + * @param string $marker The comment prefacing the target token. + * @param int $closerOffset The offset of the closer from the opener. + * @param array $expectedTags The expected tags offsets array. + * + * @dataProvider dataDocblockOpenerCloser + * + * @return void + */ + public function testDocblockOpenerCloser($marker, $closerOffset, $expectedTags) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($marker, [T_DOC_COMMENT_OPEN_TAG]); + + $opener = $tokens[$target]; + + $this->assertArrayHasKey('comment_closer', $opener, 'Comment opener: comment_closer index is not set'); + $this->assertArrayHasKey('comment_tags', $opener, 'Comment opener: comment_tags index is not set'); + + $expectedCloser = ($target + $closerOffset); + $this->assertSame($expectedCloser, $opener['comment_closer'], 'Comment opener: comment_closer not set to the expected stack pointer'); + + // Update the tags expectations. + foreach ($expectedTags as $i => $ptr) { + $expectedTags[$i] += $target; + } + + $this->assertSame($expectedTags, $opener['comment_tags'], 'Comment opener: recorded tags do not match expected tags'); + + $closer = $tokens[$opener['comment_closer']]; + + $this->assertArrayHasKey('comment_opener', $closer, 'Comment closer: comment_opener index is not set'); + $this->assertSame($target, $closer['comment_opener'], 'Comment closer: comment_opener not set to the expected stack pointer'); + + }//end testDocblockOpenerCloser() + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + abstract public static function dataDocblockOpenerCloser(); + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array> $expectedSequence The consecutive token constants and their contents to expect. + * + * @return void + */ + protected function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++, $sequenceKey++) { + $currentItem = $expectedSequence[$sequenceKey]; + $expectedCode = key($currentItem); + $expectedType = Tokens::tokenName($expectedCode); + $expectedContent = current($currentItem); + $errorMsgSuffix = PHP_EOL.'(StackPtr: '.$i.' | Position in sequence: '.$sequenceKey.' | Expected: '.$expectedType.')'; + + $this->assertSame( + $expectedCode, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedType.' (code)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedType, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedType.' (type)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedContent, + $tokens[$i]['content'], + 'Token content did not match expectations'.$errorMsgSuffix + ); + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc new file mode 100644 index 000000000..a43c7d9b2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc @@ -0,0 +1,6 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding1Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 8, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with no blank line at end of file.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc new file mode 100644 index 000000000..b113645b5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc @@ -0,0 +1,5 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding2Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock with blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 7, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with a blank line at end of file.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc new file mode 100644 index 000000000..9b81a434d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding3Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, no contents, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 1, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc new file mode 100644 index 000000000..1561e7156 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc @@ -0,0 +1,7 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding4Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, trailing whitespace on last line, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 15, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'The last line of this test must have trailing whitespace.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'So, be careful when saving this file!'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc new file mode 100644 index 000000000..f33afcd6a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc @@ -0,0 +1,81 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that multiline docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class MultiLineDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Multi line docblock: no contents' => [ + 'marker' => '/* testEmptyDocblock */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Multi line docblock: variety of text and tags' => [ + 'marker' => '/* testMultilineDocblock */', + 'closerOffset' => 95, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [21, 29, 36, 46, 56, 63, 73, 80, 90], + ], + 'Multi line docblock: no leading stars' => [ + 'marker' => '/* testMultilineDocblockNoStars */', + 'closerOffset' => 32, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [10, 16, 21, 27], + ], + 'Multi line docblock: indented' => [ + 'marker' => '/* testMultilineDocblockIndented */', + 'closerOffset' => 60, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [21, 28, 38, 45, 55], + ], + 'Multi line docblock: opener not on own line' => [ + 'marker' => '/* testMultilineDocblockOpenerNotOnOwnLine */', + 'closerOffset' => 10, + 'expectedTags' => [], + ], + 'Multi line docblock: closer not on own line' => [ + 'marker' => '/* testMultilineDocblockCloserNotOnOwnLine */', + 'closerOffset' => 11, + 'expectedTags' => [], + ], + 'Multi line docblock: stars not aligned' => [ + 'marker' => '/* testMultilineDocblockStarsNotAligned */', + 'closerOffset' => 26, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of an empty, multi-line DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testEmptyDocblock() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblock() + + + /** + * Verify tokenization of a multi-line DocBlock containing all possible tokens. + * + * @return void + */ + public function testMultilineDocblock() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line docblock.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With blank lines, stars, tags, and tag descriptions.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagWithoutDescription'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@deprecated'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '11.5'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@requires'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'PHP 7.1 -- PHPUnit tag.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag-with-dashes-is-suppported'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag_with_underscores'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblock() + + + /** + * Verify tokenization of a multi-line DocBlock with extra starts for the opener/closer and no stars on the lines between. + * + * @return void + */ + public function testMultilineDocblockNoStars() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/****'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line docblock, but the lines are not marked with stars.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Then again, the opener and closer have an abundance of stars.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '**/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockNoStars() + + + /** + * Verify tokenization of a multi-line, indented DocBlock. + * + * @return void + */ + public function testMultilineDocblockIndented() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line indented docblock.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With blank lines, stars, tags, and tag descriptions.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@deprecated'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '11.5'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockIndented() + + + /** + * Verify tokenization of a multi-line DocBlock, where the opener is not on its own line. + * + * @return void + */ + public function testMultilineDocblockOpenerNotOnOwnLine() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'description continued.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockOpenerNotOnOwnLine() + + + /** + * Verify tokenization of a multi-line DocBlock, where the closer is not on its own line. + * + * @return void + */ + public function testMultilineDocblockCloserNotOnOwnLine() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'description continued. '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockCloserNotOnOwnLine() + + + /** + * Verify tokenization of a multi-line DocBlock with inconsistent indentation. + * + * @return void + */ + public function testMultilineDocblockStarsNotAligned() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Line below this is missing a star.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Text'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Star indented.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Closer indented.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockStarsNotAligned() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc new file mode 100644 index 000000000..d74f68d24 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc @@ -0,0 +1,116 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that PHPCS native annotations in docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class PhpcsAnnotationsInDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Single-line: @phpcs:ignoreFile annotation' => [ + 'marker' => '/* testSingleLineDocIgnoreFileAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:ignore annotation' => [ + 'marker' => '/* testSingleLineDocIgnoreAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:disable annotation' => [ + 'marker' => '/* testSingleLineDocDisableAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:enable annotation; no whitespace' => [ + 'marker' => '/* testSingleLineDocEnableAnnotationNoWhitespace */', + 'closerOffset' => 2, + 'expectedTags' => [], + ], + + 'Multi-line: @phpcs:ignoreFile at the start' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:ignore at the start' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [10], + ], + 'Multi-line: @phpcs:disable at the start' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:enable at the start' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationAtStart */', + 'closerOffset' => 18, + 'expectedTags' => [13], + ], + + 'Multi-line: @phpcs:ignoreFile in the middle' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationInMiddle */', + 'closerOffset' => 21, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:ignore in the middle' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationInMiddle */', + 'closerOffset' => 23, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:disable in the middle' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationInMiddle */', + 'closerOffset' => 26, + 'expectedTags' => [21], + ], + 'Multi-line: @phpcs:enable in the middle' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationInMiddle */', + 'closerOffset' => 24, + 'expectedTags' => [21], + ], + + 'Multi-line: @phpcs:ignoreFile at the end' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:ignore at the end' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:disable at the end' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationAtEnd */', + 'closerOffset' => 18, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:enable at the end' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testSingleLineDocIgnoreFileAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocIgnoreFileAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation. + * + * @return void + */ + public function testSingleLineDocIgnoreAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName -- With reason '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocIgnoreAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation. + * + * @return void + */ + public function testSingleLineDocDisableAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName,Stnd.Other '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocDisableAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation. + * + * @return void + */ + public function testSingleLineDocEnableAnnotationNoWhitespace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat.SniffName'], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocEnableAnnotationNoWhitespace() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation at the start. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation at the start. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation at the start. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation at the start. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation in the middle. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation in the middle. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation in the middle. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagAfter'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation in the middle. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagAfter'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation at the end. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation at the end. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation at the end. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation at the end. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationAtEnd() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc new file mode 100644 index 000000000..88b05ea43 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc @@ -0,0 +1,26 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that single line docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class SingleLineDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Single line docblock: empty, no whitespace' => [ + 'marker' => '/* testEmptyDocblockNoWhiteSpace */', + 'closerOffset' => 1, + 'expectedTags' => [], + ], + 'Single line docblock: only whitespace' => [ + 'marker' => '/* testEmptyDocblockWithWhiteSpace */', + 'closerOffset' => 2, + 'expectedTags' => [], + ], + 'Single line docblock: just text' => [ + 'marker' => '/* testSingleLineDocblockNoTag */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single line docblock: @var type before name' => [ + 'marker' => '/* testSingleLineDocblockWithTag1 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + 'Single line docblock: @var name before type' => [ + 'marker' => '/* testSingleLineDocblockWithTag2 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + 'Single line docblock: @see with description' => [ + 'marker' => '/* testSingleLineDocblockWithTag3 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify an empty block comment is tokenized as T_COMMENT, not as a docblock. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testEmptyBlockCommentNoWhiteSpace() + { + $expectedSequence = [ + [T_COMMENT => '/**/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', [T_COMMENT, T_DOC_COMMENT_OPEN_TAG]); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyBlockCommentNoWhiteSpace() + + + /** + * Verify tokenization of an empty, single line DocBlock without whitespace between the opener and closer. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testEmptyDocblockNoWhiteSpace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblockNoWhiteSpace() + + + /** + * Verify tokenization of an empty, single line DocBlock. + * + * @return void + */ + public function testEmptyDocblockWithWhiteSpace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblockWithWhiteSpace() + + + /** + * Verify tokenization of a single line DocBlock. + * + * @return void + */ + public function testSingleLineDocblockNoTag() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Just some text '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockNoTag() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag1() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@var'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '\SomeClass[] $var '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag1() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag2() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@var'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '$var \SomeClass[] '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag2() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag3() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@see'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something::Else '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag3() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc new file mode 100644 index 000000000..3ee1afd0d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc @@ -0,0 +1,29 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class AnonClassParenthesisOwnerTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataAnonClassNoParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testAnonClassNoParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); + $this->assertArrayNotHasKey('parenthesis_owner', $tokens[$anonClass]); + $this->assertArrayNotHasKey('parenthesis_opener', $tokens[$anonClass]); + $this->assertArrayNotHasKey('parenthesis_closer', $tokens[$anonClass]); + + }//end testAnonClassNoParentheses() + + + /** + * Test that the next open/close parenthesis after an anonymous class without parenthesis + * do not get assigned the anonymous class as a parenthesis owner. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataAnonClassNoParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testAnonClassNoParenthesesNextOpenClose($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $function = $this->getTargetToken($testMarker, T_FUNCTION); + + $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener]); + $this->assertSame($function, $tokens[$opener]['parenthesis_owner']); + + $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer]); + $this->assertSame($function, $tokens[$closer]['parenthesis_owner']); + + }//end testAnonClassNoParenthesesNextOpenClose() + + + /** + * Data provider. + * + * @see testAnonClassNoParentheses() + * @see testAnonClassNoParenthesesNextOpenClose() + * + * @return array> + */ + public static function dataAnonClassNoParentheses() + { + return [ + 'plain' => [ + 'testMarker' => '/* testNoParentheses */', + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyNoParentheses */', + ], + 'declaration contains comments and extra whitespace' => [ + 'testMarker' => '/* testNoParenthesesAndEmptyTokens */', + ], + ]; + + }//end dataAnonClassNoParentheses() + + + /** + * Test that anonymous class tokens with parenthesis get assigned a parenthesis owner, + * opener and closer; and that the opener/closer get the anonymous class assigned as owner. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataAnonClassWithParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testAnonClassWithParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); + $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); + $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); + + $this->assertArrayHasKey('parenthesis_owner', $tokens[$anonClass]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$anonClass]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$anonClass]); + $this->assertSame($anonClass, $tokens[$anonClass]['parenthesis_owner']); + $this->assertSame($opener, $tokens[$anonClass]['parenthesis_opener']); + $this->assertSame($closer, $tokens[$anonClass]['parenthesis_closer']); + + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$opener]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$opener]); + $this->assertSame($anonClass, $tokens[$opener]['parenthesis_owner']); + $this->assertSame($opener, $tokens[$opener]['parenthesis_opener']); + $this->assertSame($closer, $tokens[$opener]['parenthesis_closer']); + + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$closer]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$closer]); + $this->assertSame($anonClass, $tokens[$closer]['parenthesis_owner']); + $this->assertSame($opener, $tokens[$closer]['parenthesis_opener']); + $this->assertSame($closer, $tokens[$closer]['parenthesis_closer']); + + }//end testAnonClassWithParentheses() + + + /** + * Data provider. + * + * @see testAnonClassWithParentheses() + * + * @return array> + */ + public static function dataAnonClassWithParentheses() + { + return [ + 'plain' => [ + 'testMarker' => '/* testWithParentheses */', + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyWithParentheses */', + ], + 'declaration contains comments and extra whitespace' => [ + 'testMarker' => '/* testWithParenthesesAndEmptyTokens */', + ], + ]; + + }//end dataAnonClassWithParentheses() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc new file mode 100644 index 000000000..6d8adfcba --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc @@ -0,0 +1,58 @@ + 10); + +/* testArrayWithComment */ +$var = Array /*comment*/ (1 => 10); + +/* testNestingArray */ +$var = array( + /* testNestedArray */ + array( + 'key' => 'value', + + /* testClosureReturnType */ + 'closure' => function($a) use($global) : Array {}, + ), +); + +/* testFunctionDeclarationParamType */ +function typedParam(array $a) {} + +/* testFunctionDeclarationReturnType */ +function returnType($a) : int|array|null {} + +class Bar { + /* testClassConst */ + const ARRAY = []; + + /* testClassMethod */ + public function array() {} + + /* testOOConstType */ + const array /* testTypedOOConstName */ ARRAY = /* testOOConstDefault */ array(); + + /* testOOPropertyType */ + protected array $property; +} + +class DNFTypes { + /* testOOConstDNFType */ + const (A&B)|array|(C&D) NAME = []; + + /* testOOPropertyDNFType */ + protected (A&B)|ARRAY|null $property; + + /* testFunctionDeclarationParamDNFType */ + public function name(null|array|(A&B) $param) { + /* testClosureDeclarationParamDNFType */ + $cl = function ( array|(A&B) $param) {}; + + /* testArrowDeclarationReturnDNFType */ + $arrow = fn($a): (A&B)|Array => new $a; + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php new file mode 100644 index 000000000..e19c2ffbf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php @@ -0,0 +1,200 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class ArrayKeywordTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the array keyword is correctly tokenized as `T_ARRAY`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)'); + $this->assertSame('T_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (type)'); + + }//end testArrayKeyword() + + + /** + * Data provider. + * + * @see testArrayKeyword() + * + * @return array> + */ + public static function dataArrayKeyword() + { + return [ + 'empty array' => [ + 'testMarker' => '/* testEmptyArray */', + ], + 'array with space before parenthesis' => [ + 'testMarker' => '/* testArrayWithSpace */', + ], + 'array with comment before parenthesis' => [ + 'testMarker' => '/* testArrayWithComment */', + 'testContent' => 'Array', + ], + 'nested: outer array' => [ + 'testMarker' => '/* testNestingArray */', + ], + 'nested: inner array' => [ + 'testMarker' => '/* testNestedArray */', + ], + 'OO constant default value' => [ + 'testMarker' => '/* testOOConstDefault */', + ], + ]; + + }//end dataArrayKeyword() + + + /** + * Test that the array keyword when used in a type declaration is correctly tokenized as `T_STRING`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayType + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testArrayType($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testArrayType() + + + /** + * Data provider. + * + * @see testArrayType() + * + * @return array> + */ + public static function dataArrayType() + { + return [ + 'closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'testContent' => 'Array', + ], + 'function param type' => [ + 'testMarker' => '/* testFunctionDeclarationParamType */', + ], + 'function union return type' => [ + 'testMarker' => '/* testFunctionDeclarationReturnType */', + ], + 'OO constant type' => [ + 'testMarker' => '/* testOOConstType */', + ], + 'OO property type' => [ + 'testMarker' => '/* testOOPropertyType */', + ], + + 'OO constant DNF type' => [ + 'testMarker' => '/* testOOConstDNFType */', + ], + 'OO property DNF type' => [ + 'testMarker' => '/* testOOPropertyDNFType */', + 'testContent' => 'ARRAY', + ], + 'function param DNF type' => [ + 'testMarker' => '/* testFunctionDeclarationParamDNFType */', + ], + 'closure param DNF type' => [ + 'testMarker' => '/* testClosureDeclarationParamDNFType */', + ], + 'arrow return DNF type' => [ + 'testMarker' => '/* testArrowDeclarationReturnDNFType */', + 'testContent' => 'Array', + ], + ]; + + }//end dataArrayType() + + + /** + * Verify that the retokenization of `T_ARRAY` tokens to `T_STRING` is handled correctly + * for tokens with the contents 'array' which aren't in actual fact the array keyword. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNotArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotArrayKeyword() + + + /** + * Data provider. + * + * @see testNotArrayKeyword() + * + * @return array> + */ + public static function dataNotArrayKeyword() + { + return [ + 'class-constant-name' => [ + 'testMarker' => '/* testClassConst */', + 'testContent' => 'ARRAY', + ], + 'class-method-name' => [ + 'testMarker' => '/* testClassMethod */', + ], + 'class-constant-name-after-type' => [ + 'testMarker' => '/* testTypedOOConstName */', + 'testContent' => 'ARRAY', + ], + ]; + + }//end dataNotArrayKeyword() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc index e539adf8a..9d56c0952 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc @@ -62,7 +62,7 @@ function multiple_attributes_on_parameter_test(#[ParamAttribute, AttributeWithPa /* testFqcnAttribute */ #[Boo\QualifiedName, \Foo\FullyQualifiedName('foo')] -function fqcn_attrebute_test() {} +function fqcn_attribute_test() {} /* testNestedAttributes */ #[Boo\QualifiedName(fn (#[AttributeOne('boo')] $value) => (string) $value)] diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php new file mode 100644 index 000000000..5e2ea0aed --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php @@ -0,0 +1,700 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class AttributesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that attributes are parsed correctly. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $tokenCodes The codes of tokens inside the attributes. + * + * @dataProvider dataAttribute + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testAttribute($testMarker, $tokenCodes) + { + $tokens = $this->phpcsFile->getTokens(); + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = (count($tokenCodes) + 1); + + $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(($attribute + $length), $closer); + + $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); + + $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); + $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); + + $map = array_map( + function ($token) use ($attribute, $length) { + $this->assertArrayHasKey('attribute_closer', $token); + $this->assertSame(($attribute + $length), $token['attribute_closer']); + + return $token['code']; + }, + array_slice($tokens, ($attribute + 1), ($length - 1)) + ); + + $this->assertSame($tokenCodes, $map); + + }//end testAttribute() + + + /** + * Data provider. + * + * @see testAttribute() + * + * @return array>> + */ + public static function dataAttribute() + { + return [ + 'class attribute' => [ + 'testMarker' => '/* testAttribute */', + 'tokenCodes' => [ + T_STRING + ], + ], + 'class attribute with param' => [ + 'testMarker' => '/* testAttributeWithParams */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_STRING, + T_DOUBLE_COLON, + T_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + 'class attribute with named param' => [ + 'testMarker' => '/* testAttributeWithNamedParam */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_STRING, + T_DOUBLE_COLON, + T_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute' => [ + 'testMarker' => '/* testAttributeOnFunction */', + 'tokenCodes' => [ + T_STRING + ], + ], + 'function attribute with params' => [ + 'testMarker' => '/* testAttributeOnFunctionWithParams */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute with arrow function as param' => [ + 'testMarker' => '/* testAttributeWithShortClosureParameter */', + 'tokenCodes' => [ + T_STRING, + T_OPEN_PARENTHESIS, + T_STATIC, + T_WHITESPACE, + T_FN, + T_WHITESPACE, + T_OPEN_PARENTHESIS, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_FN_ARROW, + T_WHITESPACE, + T_BOOLEAN_NOT, + T_WHITESPACE, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute; multiple comma separated classes' => [ + 'testMarker' => '/* testAttributeGrouping */', + 'tokenCodes' => [ + T_STRING, + T_COMMA, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_COMMA, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + ], + ], + 'function attribute; multiple comma separated classes, one per line' => [ + 'testMarker' => '/* testAttributeMultiline */', + 'tokenCodes' => [ + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_COMMA, + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_COMMA, + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + ], + ], + 'function attribute; multiple comma separated classes, one per line, with comments' => [ + 'testMarker' => '/* testAttributeMultilineWithComment */', + 'tokenCodes' => [ + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_COMMA, + T_WHITESPACE, + T_COMMENT, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_COMMENT, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_COMMA, + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + ], + ], + 'function attribute; using partially qualified and fully qualified class names' => [ + 'testMarker' => '/* testFqcnAttribute */', + 'tokenCodes' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_COMMA, + T_WHITESPACE, + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + ]; + + }//end dataAttribute() + + + /** + * Test that multiple attributes on the same line are parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testTwoAttributesOnTheSameLine() + { + $tokens = $this->phpcsFile->getTokens(); + + $attribute = $this->getTargetToken('/* testTwoAttributeOnTheSameLine */', T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); + $this->assertSame(T_ATTRIBUTE, $tokens[($closer + 2)]['code']); + $this->assertArrayHasKey('attribute_closer', $tokens[($closer + 2)]); + + }//end testTwoAttributesOnTheSameLine() + + + /** + * Test that attribute followed by a line comment is parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testAttributeAndLineComment() + { + $tokens = $this->phpcsFile->getTokens(); + + $attribute = $this->getTargetToken('/* testAttributeAndCommentOnTheSameLine */', T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); + $this->assertSame(T_COMMENT, $tokens[($closer + 2)]['code']); + + }//end testAttributeAndLineComment() + + + /** + * Test that attributes on function declaration parameters are parsed correctly. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int $position The token position (starting from T_FUNCTION) of T_ATTRIBUTE token. + * @param array $tokenCodes The codes of tokens inside the attributes. + * + * @dataProvider dataAttributeOnParameters + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testAttributeOnParameters($testMarker, $position, array $tokenCodes) + { + $tokens = $this->phpcsFile->getTokens(); + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = (count($tokenCodes) + 1); + + $function = $this->getTargetToken($testMarker, T_FUNCTION); + $attribute = ($function + $position); + + $this->assertSame(T_ATTRIBUTE, $tokens[$attribute]['code']); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $this->assertSame(($attribute + $length), $tokens[$attribute]['attribute_closer']); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(T_WHITESPACE, $tokens[($closer + 1)]['code']); + $this->assertSame(T_STRING, $tokens[($closer + 2)]['code']); + $this->assertSame('int', $tokens[($closer + 2)]['content']); + + $this->assertSame(T_VARIABLE, $tokens[($closer + 4)]['code']); + $this->assertSame('$param', $tokens[($closer + 4)]['content']); + + $map = array_map( + function ($token) use ($attribute, $length) { + $this->assertArrayHasKey('attribute_closer', $token); + $this->assertSame(($attribute + $length), $token['attribute_closer']); + + return $token['code']; + }, + array_slice($tokens, ($attribute + 1), ($length - 1)) + ); + + $this->assertSame($tokenCodes, $map); + + }//end testAttributeOnParameters() + + + /** + * Data provider. + * + * @see testAttributeOnParameters() + * + * @return array>> + */ + public static function dataAttributeOnParameters() + { + return [ + 'parameter attribute; single, inline' => [ + 'testMarker' => '/* testSingleAttributeOnParameter */', + 'position' => 4, + 'tokenCodes' => [ + T_STRING + ], + ], + 'parameter attribute; multiple comma separated, inline' => [ + 'testMarker' => '/* testMultipleAttributesOnParameter */', + 'position' => 4, + 'tokenCodes' => [ + T_STRING, + T_COMMA, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_COMMENT, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + ], + ], + 'parameter attribute; single, multiline' => [ + 'testMarker' => '/* testMultilineAttributesOnParameter */', + 'position' => 4, + 'tokenCodes' => [ + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_WHITESPACE, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_WHITESPACE, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_WHITESPACE, + ], + ], + ]; + + }//end dataAttributeOnParameters() + + + /** + * Test that an attribute containing text which looks like a PHP close tag is tokenized correctly. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokensAttribute The codes of tokens inside the attributes. + * @param array $expectedTokensAfter The codes of tokens after the attributes. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @dataProvider dataAttributeOnTextLookingLikeCloseTag + * + * @return void + */ + public function testAttributeContainingTextLookingLikeCloseTag($testMarker, array $expectedTokensAttribute, array $expectedTokensAfter) + { + $tokens = $this->phpcsFile->getTokens(); + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = count($expectedTokensAttribute); + + $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); + + $this->assertSame('T_ATTRIBUTE', $tokens[$attribute]['type']); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(($attribute + $length), $closer); + $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); + $this->assertSame('T_ATTRIBUTE_END', $tokens[$closer]['type']); + + $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); + $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); + + $i = ($attribute + 1); + foreach ($expectedTokensAttribute as $item) { + list($expectedType, $expectedContents) = $item; + $this->assertSame($expectedType, $tokens[$i]['type']); + $this->assertSame($expectedContents, $tokens[$i]['content']); + $this->assertArrayHasKey('attribute_opener', $tokens[$i]); + $this->assertArrayHasKey('attribute_closer', $tokens[$i]); + ++$i; + } + + $i = ($closer + 1); + foreach ($expectedTokensAfter as $expectedCode) { + $this->assertSame($expectedCode, $tokens[$i]['code']); + ++$i; + } + + }//end testAttributeContainingTextLookingLikeCloseTag() + + + /** + * Data provider. + * + * @see dataAttributeOnTextLookingLikeCloseTag() + * + * @return array>|array>> + */ + public static function dataAttributeOnTextLookingLikeCloseTag() + { + return [ + 'function attribute; string param with "?>"' => [ + 'testMarker' => '/* testAttributeContainingTextLookingLikeCloseTag */', + 'expectedTokensAttribute' => [ + [ + 'T_STRING', + 'DeprecationReason', + ], + [ + 'T_OPEN_PARENTHESIS', + '(', + ], + [ + 'T_CONSTANT_ENCAPSED_STRING', + "'reason: '", + ], + [ + 'T_CLOSE_PARENTHESIS', + ')', + ], + [ + 'T_ATTRIBUTE_END', + ']', + ], + ], + 'expectedTokensAfter' => [ + T_WHITESPACE, + T_FUNCTION, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ], + ], + 'function attribute; string param with "?>"; multiline' => [ + 'testMarker' => '/* testAttributeContainingMultilineTextLookingLikeCloseTag */', + 'expectedTokensAttribute' => [ + [ + 'T_STRING', + 'DeprecationReason', + ], + [ + 'T_OPEN_PARENTHESIS', + '(', + ], + [ + 'T_WHITESPACE', + "\n", + ], + [ + 'T_WHITESPACE', + " ", + ], + [ + 'T_CONSTANT_ENCAPSED_STRING', + "'reason: '", + ], + [ + 'T_WHITESPACE', + "\n", + ], + [ + 'T_CLOSE_PARENTHESIS', + ')', + ], + [ + 'T_ATTRIBUTE_END', + ']', + ], + ], + 'expectedTokensAfter' => [ + T_WHITESPACE, + T_FUNCTION, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ], + ], + ]; + + }//end dataAttributeOnTextLookingLikeCloseTag() + + + /** + * Test that invalid attribute (or comment starting with #[ and without ]) are parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * + * @return void + */ + public function testInvalidAttribute() + { + $tokens = $this->phpcsFile->getTokens(); + + $attribute = $this->getTargetToken('/* testInvalidAttribute */', T_ATTRIBUTE); + + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + $this->assertNull($tokens[$attribute]['attribute_closer']); + + }//end testInvalidAttribute() + + + /** + * Test that nested attributes are parsed correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser + * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * @covers PHP_CodeSniffer\Tokenizers\PHP::createAttributesNestingMap + * + * @return void + */ + public function testNestedAttributes() + { + $tokens = $this->phpcsFile->getTokens(); + $tokenCodes = [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_OPEN_PARENTHESIS, + T_FN, + T_WHITESPACE, + T_OPEN_PARENTHESIS, + T_ATTRIBUTE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_ATTRIBUTE_END, + T_WHITESPACE, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + T_FN_ARROW, + T_WHITESPACE, + T_STRING_CAST, + T_WHITESPACE, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + ]; + + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $outerAttributeLength = (count($tokenCodes) + 1); + + $attribute = $this->getTargetToken('/* testNestedAttributes */', T_ATTRIBUTE); + $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); + + $closer = $tokens[$attribute]['attribute_closer']; + $this->assertSame(($attribute + $outerAttributeLength), $closer); + + $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); + + $this->assertSame($tokens[$attribute]['attribute_opener'], $tokens[$closer]['attribute_opener']); + $this->assertSame($tokens[$attribute]['attribute_closer'], $tokens[$closer]['attribute_closer']); + + $this->assertArrayNotHasKey('nested_attributes', $tokens[$attribute]); + $this->assertArrayHasKey('nested_attributes', $tokens[($attribute + 8)]); + $this->assertSame([$attribute => ($attribute + $outerAttributeLength)], $tokens[($attribute + 8)]['nested_attributes']); + + $test = function (array $tokens, $outerAttributeLength, $nestedMap) use ($attribute) { + foreach ($tokens as $token) { + $this->assertArrayHasKey('attribute_closer', $token); + $this->assertSame(($attribute + $outerAttributeLength), $token['attribute_closer']); + $this->assertSame($nestedMap, $token['nested_attributes']); + } + }; + + // Length here is 8 (nested attribute offset) + 5 (real length). + $innerAttributeLength = (8 + 5); + + $test(array_slice($tokens, ($attribute + 1), 7), $outerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + $test(array_slice($tokens, ($attribute + 8), 1), $innerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + + $test( + array_slice($tokens, ($attribute + 9), 4), + $innerAttributeLength, + [ + $attribute => $attribute + $outerAttributeLength, + $attribute + 8 => $attribute + 13, + ] + ); + + $test(array_slice($tokens, ($attribute + 13), 1), $innerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + $test(array_slice($tokens, ($attribute + 14), 10), $outerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + + $map = array_map( + static function ($token) { + return $token['code']; + }, + array_slice($tokens, ($attribute + 1), ($outerAttributeLength - 1)) + ); + + $this->assertSame($tokenCodes, $map); + + }//end testNestedAttributes() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc index 82bfe24fd..16624ecce 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc @@ -66,10 +66,6 @@ enum /* comment */ Name case SOME_CASE; } -enum /* testEnumUsedAsEnumName */ Enum -{ -} - /* testEnumUsedAsNamespaceName */ namespace Enum; /* testEnumUsedAsPartOfNamespaceName */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php new file mode 100644 index 000000000..9b313ca69 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php @@ -0,0 +1,226 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillEnumTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the "enum" keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent The token content to look for. + * @param int $openerOffset Offset to find expected scope opener. + * @param int $closerOffset Offset to find expected scope closer. + * + * @dataProvider dataEnums + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testEnums($testMarker, $testContent, $openerOffset, $closerOffset) + { + $tokens = $this->phpcsFile->getTokens(); + $enum = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); + $tokenArray = $tokens[$enum]; + + $this->assertSame(T_ENUM, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM (code)'); + $this->assertSame('T_ENUM', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM (type)'); + + $this->assertArrayHasKey('scope_condition', $tokenArray); + $this->assertArrayHasKey('scope_opener', $tokenArray); + $this->assertArrayHasKey('scope_closer', $tokenArray); + + $this->assertSame($enum, $tokenArray['scope_condition']); + + $scopeOpener = $tokenArray['scope_opener']; + $scopeCloser = $tokenArray['scope_closer']; + + $expectedScopeOpener = ($enum + $openerOffset); + $expectedScopeCloser = ($enum + $closerOffset); + + $this->assertSame($expectedScopeOpener, $scopeOpener); + $this->assertArrayHasKey('scope_condition', $tokens[$scopeOpener]); + $this->assertArrayHasKey('scope_opener', $tokens[$scopeOpener]); + $this->assertArrayHasKey('scope_closer', $tokens[$scopeOpener]); + $this->assertSame($enum, $tokens[$scopeOpener]['scope_condition']); + $this->assertSame($scopeOpener, $tokens[$scopeOpener]['scope_opener']); + $this->assertSame($scopeCloser, $tokens[$scopeOpener]['scope_closer']); + + $this->assertSame($expectedScopeCloser, $scopeCloser); + $this->assertArrayHasKey('scope_condition', $tokens[$scopeCloser]); + $this->assertArrayHasKey('scope_opener', $tokens[$scopeCloser]); + $this->assertArrayHasKey('scope_closer', $tokens[$scopeCloser]); + $this->assertSame($enum, $tokens[$scopeCloser]['scope_condition']); + $this->assertSame($scopeOpener, $tokens[$scopeCloser]['scope_opener']); + $this->assertSame($scopeCloser, $tokens[$scopeCloser]['scope_closer']); + + }//end testEnums() + + + /** + * Data provider. + * + * @see testEnums() + * + * @return array> + */ + public static function dataEnums() + { + return [ + 'enum - pure' => [ + 'testMarker' => '/* testPureEnum */', + 'testContent' => 'enum', + 'openerOffset' => 4, + 'closerOffset' => 12, + ], + 'enum - backed int' => [ + 'testMarker' => '/* testBackedIntEnum */', + 'testContent' => 'enum', + 'openerOffset' => 7, + 'closerOffset' => 29, + ], + 'enum - backed string' => [ + 'testMarker' => '/* testBackedStringEnum */', + 'testContent' => 'enum', + 'openerOffset' => 8, + 'closerOffset' => 30, + ], + 'enum - backed int + implements' => [ + 'testMarker' => '/* testComplexEnum */', + 'testContent' => 'enum', + 'openerOffset' => 11, + 'closerOffset' => 72, + ], + 'enum keyword when "enum" is the name for the construct (yes, this is allowed)' => [ + 'testMarker' => '/* testEnumWithEnumAsClassName */', + 'testContent' => 'enum', + 'openerOffset' => 6, + 'closerOffset' => 7, + ], + 'enum - keyword is case insensitive' => [ + 'testMarker' => '/* testEnumIsCaseInsensitive */', + 'testContent' => 'EnUm', + 'openerOffset' => 4, + 'closerOffset' => 5, + ], + 'enum - declaration containing comment' => [ + 'testMarker' => '/* testDeclarationContainingComment */', + 'testContent' => 'enum', + 'openerOffset' => 6, + 'closerOffset' => 14, + ], + ]; + + }//end dataEnums() + + + /** + * Test that "enum" when not used as the keyword is still tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotEnums + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNotEnums($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotEnums() + + + /** + * Data provider. + * + * @see testNotEnums() + * + * @return array> + */ + public static function dataNotEnums() + { + return [ + 'not enum - construct named enum' => [ + 'testMarker' => '/* testEnumAsClassNameAfterEnumKeyword */', + 'testContent' => 'Enum', + ], + 'not enum - class named enum' => [ + 'testMarker' => '/* testEnumUsedAsClassName */', + 'testContent' => 'Enum', + ], + 'not enum - class constant named enum' => [ + 'testMarker' => '/* testEnumUsedAsClassConstantName */', + 'testContent' => 'ENUM', + ], + 'not enum - method named enum' => [ + 'testMarker' => '/* testEnumUsedAsMethodName */', + 'testContent' => 'enum', + ], + 'not enum - class property named enum' => [ + 'testMarker' => '/* testEnumUsedAsPropertyName */', + 'testContent' => 'enum', + ], + 'not enum - global function named enum' => [ + 'testMarker' => '/* testEnumUsedAsFunctionName */', + 'testContent' => 'enum', + ], + 'not enum - namespace named enum' => [ + 'testMarker' => '/* testEnumUsedAsNamespaceName */', + 'testContent' => 'Enum', + ], + 'not enum - part of namespace named enum' => [ + 'testMarker' => '/* testEnumUsedAsPartOfNamespaceName */', + 'testContent' => 'Enum', + ], + 'not enum - class instantiation for class enum' => [ + 'testMarker' => '/* testEnumUsedInObjectInitialization */', + 'testContent' => 'Enum', + ], + 'not enum - function call' => [ + 'testMarker' => '/* testEnumAsFunctionCall */', + 'testContent' => 'enum', + ], + 'not enum - namespace relative function call' => [ + 'testMarker' => '/* testEnumAsFunctionCallWithNamespace */', + 'testContent' => 'enum', + ], + 'not enum - class constant fetch with enum as class name' => [ + 'testMarker' => '/* testClassConstantFetchWithEnumAsClassName */', + 'testContent' => 'Enum', + ], + 'not enum - class constant fetch with enum as constant name' => [ + 'testMarker' => '/* testClassConstantFetchWithEnumAsConstantName */', + 'testContent' => 'ENUM', + ], + 'parse error, not enum - enum declaration without name' => [ + 'testMarker' => '/* testParseErrorMissingName */', + 'testContent' => 'enum', + ], + 'parse error, not enum - enum declaration with curlies' => [ + 'testMarker' => '/* testParseErrorLiveCoding */', + 'testContent' => 'enum', + ], + ]; + + }//end dataNotEnums() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc similarity index 92% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc index 154d48950..eb907ed39 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc @@ -26,3 +26,6 @@ $foo = 0o28_2; /* testInvalid6 */ $foo = 0o2_82; + +/* testInvalid7 */ +$foo = 0o; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.php new file mode 100644 index 000000000..7dc3e1392 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.php @@ -0,0 +1,120 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillExplicitOctalNotationTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that explicitly-defined octal values are tokenized as a single number and not as a number and a string. + * + * @param string $marker The comment which prefaces the target token in the test file. + * @param string $value The expected content of the token. + * @param int|string $nextToken The expected next token. + * @param string $nextContent The expected content of the next token. + * + * @dataProvider dataExplicitOctalNotation + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testExplicitOctalNotation($marker, $value, $nextToken, $nextContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $number = $this->getTargetToken($marker, [T_LNUMBER]); + + $this->assertSame($value, $tokens[$number]['content'], 'Content of integer token does not match expectation'); + + $this->assertSame($nextToken, $tokens[($number + 1)]['code'], 'Next token is not the expected type, but '.$tokens[($number + 1)]['type']); + $this->assertSame($nextContent, $tokens[($number + 1)]['content'], 'Next token did not have the expected contents'); + + }//end testExplicitOctalNotation() + + + /** + * Data provider. + * + * @see testExplicitOctalNotation() + * + * @return array> + */ + public static function dataExplicitOctalNotation() + { + return [ + 'Explicit octal' => [ + 'marker' => '/* testExplicitOctal */', + 'value' => '0o137041', + 'nextToken' => T_SEMICOLON, + 'nextContent' => ';', + ], + 'Explicit octal - capitalized O' => [ + 'marker' => '/* testExplicitOctalCapitalised */', + 'value' => '0O137041', + 'nextToken' => T_SEMICOLON, + 'nextContent' => ';', + ], + 'Explicit octal - with numeric literal separator' => [ + 'marker' => '/* testExplicitOctalWithNumericSeparator */', + 'value' => '0o137_041', + 'nextToken' => T_SEMICOLON, + 'nextContent' => ';', + ], + 'Invalid explicit octal - numeric literal separator directly after "0o"' => [ + 'marker' => '/* testInvalid1 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'o_137', + ], + 'Invalid explicit octal - numeric literal separator directly after "0O" (capitalized O)' => [ + 'marker' => '/* testInvalid2 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'O_41', + ], + 'Invalid explicit octal - number out of octal range' => [ + 'marker' => '/* testInvalid3 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'o91', + ], + 'Invalid explicit octal - part of the number out of octal range' => [ + 'marker' => '/* testInvalid4 */', + 'value' => '0O2', + 'nextToken' => T_LNUMBER, + 'nextContent' => '82', + ], + 'Invalid explicit octal - part of the number out of octal range with numeric literal separator after' => [ + 'marker' => '/* testInvalid5 */', + 'value' => '0o2', + 'nextToken' => T_LNUMBER, + 'nextContent' => '8_2', + ], + 'Invalid explicit octal - part of the number out of octal range with numeric literal separator before' => [ + 'marker' => '/* testInvalid6 */', + 'value' => '0o2', + 'nextToken' => T_STRING, + 'nextContent' => '_82', + ], + 'Invalid explicit octal - explicit notation without number' => [ + 'marker' => '/* testInvalid7 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'o', + ], + ]; + + }//end dataExplicitOctalNotation() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc new file mode 100644 index 000000000..ce247e991 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc @@ -0,0 +1,5 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillFnTokenParseErrorTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that un unfinished arrow function during live coding doesn't cause a "Undefined array key "parenthesis_closer"" error. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnfinishedArrowFunction() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testLiveCoding */', [T_STRING, T_FN], 'fn'); + $tokenArray = $tokens[$token]; + + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testUnfinishedArrowFunction() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc index 13f165b77..8930d4fbf 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc @@ -71,10 +71,10 @@ $a = [ /* testYield */ $a = fn($x) => yield 'k' => $x; -/* testNullableNamespace */ +/* testNullableUnqualifiedClassName */ $a = fn(?\DateTime $x) : ?\DateTime => $x; -/* testNamespaceOperatorInTypes */ +/* testNamespaceRelativeClassNameInTypes */ $fn = fn(namespace\Foo $a) : ?namespace\Foo => $a; /* testSelfReturnType */ @@ -92,12 +92,42 @@ fn(array $a) : array => $a; /* testStaticReturnType */ fn(array $a) : static => $a; +/* testFalseReturnType */ +fn(array $a) : false => $a; + +/* testTrueReturnType */ +fn(array $a) : True => $a; + +/* testNullReturnType */ +fn(array $a) : null => $a; + /* testUnionParamType */ $arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param); /* testUnionReturnType */ $arrowWithUnionReturn = fn($param) : int|float => $param | 10; +/* testUnionReturnTypeWithTrue */ +$arrowWithUnionReturn = fn($param) : int|true => $param | 10; + +/* testUnionReturnTypeWithFalse */ +$arrowWithUnionReturn = fn($param) : string|FALSE => $param | 10; + +/* testIntersectionParamType */ +$arrowWithIntersectionParam = fn(Traversable&Countable $param) : int => (new SomeClass($param))->getValue(); + +/* testIntersectionReturnType */ +$arrowWithIntersectionReturn = fn($param) : \MyFoo&SomeInterface => new SomeClass($param); + +/* testDNFParamType */ +$arrowWithDNFParam = fn((Traversable&Countable)|null $param) : SomeClass => new SomeClass($param) ?? null; + +/* testDNFReturnType */ +$arrowWithDNFReturn = fn($param) : false|(\MyFoo&SomeInterface) => new \MyFoo($param) ?? false; + +/* testDNFParamTypeWithReturnByRef */ +$arrowWithDNFParamReturnByRef = fn &((A&B)|null $param) => $param * 10; + /* testTernary */ $fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b'; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php new file mode 100644 index 000000000..d5cf019b8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php @@ -0,0 +1,967 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillFnTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Test simple arrow functions. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataSimple + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSimple($testMarker) + { + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 12); + + }//end testSimple() + + + /** + * Data provider. + * + * @see testSimple() + * + * @return array> + */ + public static function dataSimple() + { + return [ + 'standard' => [ + 'testMarker' => '/* testStandard */', + ], + 'mixed case' => [ + 'testMarker' => '/* testMixedCase */', + ], + ]; + + }//end dataSimple() + + + /** + * Test whitespace inside arrow function definitions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testWhitespace() + { + $token = $this->getTargetToken('/* testWhitespace */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 6, 13); + + }//end testWhitespace() + + + /** + * Test comments inside arrow function definitions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testComment() + { + $token = $this->getTargetToken('/* testComment */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 8, 15); + + }//end testComment() + + + /** + * Test heredocs inside arrow function definitions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testHeredoc() + { + $token = $this->getTargetToken('/* testHeredoc */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 9); + + }//end testHeredoc() + + + /** + * Test nested arrow functions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedOuter() + { + $token = $this->getTargetToken('/* testNestedOuter */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 25); + + }//end testNestedOuter() + + + /** + * Test nested arrow functions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedInner() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testNestedInner */', T_FN); + $this->backfillHelper($token, true); + + $expectedScopeOpener = ($token + 5); + $expectedScopeCloser = ($token + 16); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the semicolon token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token of the "outer" arrow function (shared scope closer)'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the semicolon token'); + + }//end testNestedInner() + + + /** + * Test nested arrow functions with a shared closer. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedSharedCloser() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testNestedSharedCloserOuter */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 20); + + $token = $this->getTargetToken('/* testNestedSharedCloserInner */', T_FN); + $this->backfillHelper($token, true); + + $expectedScopeOpener = ($token + 4); + $expectedScopeCloser = ($token + 12); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for "inner" arrow function is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for "inner" arrow function is not the TRUE token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for "inner" arrow function is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for "inner" arrow function is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame(($token - 4), $tokens[$closer]['scope_opener'], 'Closer scope opener for "inner" arrow function is not the arrow token of the "outer" arrow function (shared scope closer)'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for "inner" arrow function is not the TRUE token'); + + }//end testNestedSharedCloser() + + + /** + * Test arrow functions that call functions. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testFunctionCall() + { + $token = $this->getTargetToken('/* testFunctionCall */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 17); + + }//end testFunctionCall() + + + /** + * Test arrow functions that are included in chained calls. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testChainedFunctionCall() + { + $token = $this->getTargetToken('/* testChainedFunctionCall */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 12, 'bracket'); + + }//end testChainedFunctionCall() + + + /** + * Test arrow functions that are used as function arguments. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testFunctionArgument() + { + $token = $this->getTargetToken('/* testFunctionArgument */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 8, 15, 'comma'); + + }//end testFunctionArgument() + + + /** + * Test arrow functions that use closures. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testClosure() + { + $token = $this->getTargetToken('/* testClosure */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 60, 'comma'); + + }//end testClosure() + + + /** + * Test arrow functions using an array index. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testArrayIndex() + { + $token = $this->getTargetToken('/* testArrayIndex */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 8, 17, 'comma'); + + }//end testArrayIndex() + + + /** + * Test arrow functions with a return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testReturnType() + { + $token = $this->getTargetToken('/* testReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18, 'comma'); + + }//end testReturnType() + + + /** + * Test arrow functions that return a reference. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testReference() + { + $token = $this->getTargetToken('/* testReference */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 6, 9); + + }//end testReference() + + + /** + * Test arrow functions that are grouped by parenthesis. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testGrouped() + { + $token = $this->getTargetToken('/* testGrouped */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 8); + + }//end testGrouped() + + + /** + * Test arrow functions that are used as array values. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testArrayValue() + { + $token = $this->getTargetToken('/* testArrayValue */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 9, 'comma'); + + }//end testArrayValue() + + + /** + * Test arrow functions that are used as array values with no trailing comma. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testArrayValueNoTrailingComma() + { + $token = $this->getTargetToken('/* testArrayValueNoTrailingComma */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 4, 8, 'closing parenthesis'); + + }//end testArrayValueNoTrailingComma() + + + /** + * Test arrow functions that use the yield keyword. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testYield() + { + $token = $this->getTargetToken('/* testYield */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 14); + + }//end testYield() + + + /** + * Test arrow functions that use nullable type with unqualified class name. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNullableUnqualifiedClassName() + { + $token = $this->getTargetToken('/* testNullableUnqualifiedClassName */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 15, 18); + + }//end testNullableUnqualifiedClassName() + + + /** + * Test arrow functions that use namespace relative class name in the return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNamespaceRelativeClassNameInTypes() + { + $token = $this->getTargetToken('/* testNamespaceRelativeClassNameInTypes */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 16, 19); + + }//end testNamespaceRelativeClassNameInTypes() + + + /** + * Test arrow functions that use keyword return types. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataKeywordReturnTypes + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testKeywordReturnTypes($testMarker) + { + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 14); + + }//end testKeywordReturnTypes() + + + /** + * Data provider. + * + * @see testKeywordReturnTypes() + * + * @return array> + */ + public static function dataKeywordReturnTypes() + { + return [ + 'self' => [ + 'testMarker' => '/* testSelfReturnType */', + ], + 'parent' => [ + 'testMarker' => '/* testParentReturnType */', + ], + 'callable' => [ + 'testMarker' => '/* testCallableReturnType */', + ], + 'array' => [ + 'testMarker' => '/* testArrayReturnType */', + ], + 'static' => [ + 'testMarker' => '/* testStaticReturnType */', + ], + 'false' => [ + 'testMarker' => '/* testFalseReturnType */', + ], + 'true' => [ + 'testMarker' => '/* testTrueReturnType */', + ], + 'null' => [ + 'testMarker' => '/* testNullReturnType */', + ], + ]; + + }//end dataKeywordReturnTypes() + + + /** + * Test arrow function with a union parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionParamType() + { + $token = $this->getTargetToken('/* testUnionParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 13, 21); + + }//end testUnionParamType() + + + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnType() + { + $token = $this->getTargetToken('/* testUnionReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnType() + + + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnTypeWithTrue() + { + $token = $this->getTargetToken('/* testUnionReturnTypeWithTrue */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnTypeWithTrue() + + + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnTypeWithFalse() + { + $token = $this->getTargetToken('/* testUnionReturnTypeWithFalse */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnTypeWithFalse() + + + /** + * Test arrow function with an intersection parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testIntersectionParamType() + { + $token = $this->getTargetToken('/* testIntersectionParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 13, 27); + + }//end testIntersectionParamType() + + + /** + * Test arrow function with an intersection return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testIntersectionReturnType() + { + $token = $this->getTargetToken('/* testIntersectionReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 12, 20); + + }//end testIntersectionReturnType() + + + /** + * Test arrow function with a DNF parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFParamType() + { + $token = $this->getTargetToken('/* testDNFParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 17, 29); + + }//end testDNFParamType() + + + /** + * Test arrow function with a DNF return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFReturnType() + { + $token = $this->getTargetToken('/* testDNFReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 16, 29); + + }//end testDNFReturnType() + + + /** + * Test arrow function which returns by reference with a DNF parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFParamTypeWithReturnByRef() + { + $token = $this->getTargetToken('/* testDNFParamTypeWithReturnByRef */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 15, 22); + + }//end testDNFParamTypeWithReturnByRef() + + + /** + * Test arrow functions used in ternary operators. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTernary() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testTernary */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 40); + + $token = $this->getTargetToken('/* testTernaryThen */', T_FN); + $this->backfillHelper($token); + + $expectedScopeOpener = ($token + 8); + $expectedScopeCloser = ($token + 12); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for THEN is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for THEN is not the semicolon token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for THEN is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for THEN is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener for THEN is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for THEN is not the semicolon token'); + + $token = $this->getTargetToken('/* testTernaryElse */', T_FN); + $this->backfillHelper($token, true); + + $expectedScopeOpener = ($token + 8); + $expectedScopeCloser = ($token + 11); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener for ELSE is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer for ELSE is not the semicolon token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener for ELSE is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer for ELSE is not the semicolon token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame(($token - 24), $tokens[$closer]['scope_opener'], 'Closer scope opener for ELSE is not the arrow token of the "outer" arrow function (shared scope closer)'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer for ELSE is not the semicolon token'); + + }//end testTernary() + + + /** + * Test typed arrow functions used in ternary operators. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTernaryWithTypes() + { + $token = $this->getTargetToken('/* testTernaryWithTypes */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 15, 27); + + }//end testTernaryWithTypes() + + + /** + * Test arrow function returning a match control structure. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testWithMatchValue() + { + $token = $this->getTargetToken('/* testWithMatchValue */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 44); + + }//end testWithMatchValue() + + + /** + * Test arrow function returning a match control structure with something behind it. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testWithMatchValueAndMore() + { + $token = $this->getTargetToken('/* testWithMatchValueAndMore */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 48); + + }//end testWithMatchValueAndMore() + + + /** + * Test match control structure returning arrow functions. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * @param string $expectedCloserType The type of token expected for the scope closer. + * @param string $expectedCloserFriendlyName A friendly name for the type of token expected for the scope closer + * to be used in the error message for failing tests. + * + * @dataProvider dataInMatchValue + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testInMatchValue($testMarker, $openerOffset, $closerOffset, $expectedCloserType, $expectedCloserFriendlyName) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserFriendlyName); + + $this->assertSame($expectedCloserType, $tokens[($token + $closerOffset)]['type'], 'Mismatched scope closer type'); + + }//end testInMatchValue() + + + /** + * Data provider. + * + * @see testInMatchValue() + * + * @return array> + */ + public static function dataInMatchValue() + { + return [ + 'not_last_value' => [ + 'testMarker' => '/* testInMatchNotLastValue */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_COMMA', + 'expectedCloserFriendlyName' => 'comma', + ], + 'last_value_with_trailing_comma' => [ + 'testMarker' => '/* testInMatchLastValueWithTrailingComma */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_COMMA', + 'expectedCloserFriendlyName' => 'comma', + ], + 'last_value_without_trailing_comma_1' => [ + 'testMarker' => '/* testInMatchLastValueNoTrailingComma1 */', + 'openerOffset' => 5, + 'closerOffset' => 10, + 'expectedCloserType' => 'T_CLOSE_PARENTHESIS', + 'expectedCloserFriendlyName' => 'close parenthesis', + ], + 'last_value_without_trailing_comma_2' => [ + 'testMarker' => '/* testInMatchLastValueNoTrailingComma2 */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_VARIABLE', + 'expectedCloserFriendlyName' => '$y variable', + ], + ]; + + }//end dataInMatchValue() + + + /** + * Test arrow function nested within a method declaration. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNestedInMethod() + { + $token = $this->getTargetToken('/* testNestedInMethod */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 17); + + }//end testNestedInMethod() + + + /** + * Verify that "fn" keywords which are not arrow functions get tokenized as T_STRING and don't + * have the extra token array indexes. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotAnArrowFunction + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotAnArrowFunction($testMarker, $testContent='fn') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_STRING, T_FN], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testNotAnArrowFunction() + + + /** + * Data provider. + * + * @see testNotAnArrowFunction() + * + * @return array> + */ + public static function dataNotAnArrowFunction() + { + return [ + 'name of a function, context: declaration' => [ + 'testMarker' => '/* testFunctionName */', + ], + 'name of a constant, context: declaration using "const" keyword - uppercase' => [ + 'testMarker' => '/* testConstantDeclaration */', + 'testContent' => 'FN', + ], + 'name of a constant, context: declaration using "const" keyword - lowercase' => [ + 'testMarker' => '/* testConstantDeclarationLower */', + 'testContent' => 'fn', + ], + 'name of a (static) method, context: declaration' => [ + 'testMarker' => '/* testStaticMethodName */', + ], + 'name of a property, context: property access' => [ + 'testMarker' => '/* testPropertyAssignment */', + ], + 'name of a method, context: declaration in an anon class - mixed case' => [ + 'testMarker' => '/* testAnonClassMethodName */', + 'testContent' => 'fN', + ], + 'name of a method, context: static method call' => [ + 'testMarker' => '/* testNonArrowStaticMethodCall */', + ], + 'name of a constant, context: constant access - uppercase' => [ + 'testMarker' => '/* testNonArrowConstantAccess */', + 'testContent' => 'FN', + ], + 'name of a constant, context: constant access - mixed case' => [ + 'testMarker' => '/* testNonArrowConstantAccessMixed */', + 'testContent' => 'Fn', + ], + 'name of a method, context: method call on object - lowercase' => [ + 'testMarker' => '/* testNonArrowObjectMethodCall */', + ], + 'name of a method, context: method call on object - uppercase' => [ + 'testMarker' => '/* testNonArrowObjectMethodCallUpper */', + 'testContent' => 'FN', + ], + 'name of a (namespaced) function, context: partially qualified function call' => [ + 'testMarker' => '/* testNonArrowNamespacedFunctionCall */', + 'testContent' => 'Fn', + ], + 'name of a (namespaced) function, context: namespace relative function call' => [ + 'testMarker' => '/* testNonArrowNamespaceOperatorFunctionCall */', + ], + 'name of a function, context: declaration with union types for param and return' => [ + 'testMarker' => '/* testNonArrowFunctionNameWithUnionTypes */', + ], + 'unknown - live coding/parse error' => [ + 'testMarker' => '/* testLiveCoding */', + ], + ]; + + }//end dataNotAnArrowFunction() + + + /** + * Helper function to check that all token keys are correctly set for T_FN tokens. + * + * @param int $token The T_FN token to check. + * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. + * This should be set to "true" when testing nested arrow functions, + * where the "inner" arrow function shares a scope closer with the + * "outer" arrow function, as the 'scope_condition' for the scope closer + * of the "inner" arrow function will point to the "outer" arrow function. + * + * @return void + */ + private function backfillHelper($token, $skipScopeCloserCheck=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $this->assertArrayHasKey('scope_condition', $tokens[$token], 'Scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$token], 'Scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$token], 'Scope closer is not set'); + $this->assertSame($tokens[$token]['scope_condition'], $token, 'Scope condition is not the T_FN token'); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$token], 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$token], 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$token], 'Parenthesis closer is not set'); + $this->assertSame($tokens[$token]['parenthesis_owner'], $token, 'Parenthesis owner is not the T_FN token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); + $this->assertSame($tokens[$opener]['scope_condition'], $token, 'Opener scope condition is not the T_FN token'); + $this->assertSame(T_FN_ARROW, $tokens[$opener]['code'], 'Arrow scope opener not tokenized as T_FN_ARROW (code)'); + $this->assertSame('T_FN_ARROW', $tokens[$opener]['type'], 'Arrow scope opener not tokenized as T_FN_ARROW (type)'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); + if ($skipScopeCloserCheck === false) { + $this->assertSame($tokens[$closer]['scope_condition'], $token, 'Closer scope condition is not the T_FN token'); + } + + $opener = $tokens[$token]['parenthesis_opener']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener], 'Opening parenthesis owner is not set'); + $this->assertSame($tokens[$opener]['parenthesis_owner'], $token, 'Opening parenthesis owner is not the T_FN token'); + + $closer = $tokens[$token]['parenthesis_closer']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer], 'Closing parenthesis owner is not set'); + $this->assertSame($tokens[$closer]['parenthesis_owner'], $token, 'Closing parenthesis owner is not the T_FN token'); + + }//end backfillHelper() + + + /** + * Helper function to check that the scope opener/closer positions are correctly set for T_FN tokens. + * + * @param int $token The T_FN token to check. + * @param int $openerOffset The expected offset of the scope opener in relation to + * the fn keyword. + * @param int $closerOffset The expected offset of the scope closer in relation to + * the fn keyword. + * @param string $expectedCloserType Optional. The type of token expected for the scope closer. + * + * @return void + */ + private function scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserType='semicolon') + { + $tokens = $this->phpcsFile->getTokens(); + $expectedScopeOpener = ($token + $openerOffset); + $expectedScopeCloser = ($token + $closerOffset); + + $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], 'Scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], 'Scope closer is not the '.$expectedCloserType.' token'); + + $opener = $tokens[$token]['scope_opener']; + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'Opener scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'Opener scope closer is not the '.$expectedCloserType.' token'); + + $closer = $tokens[$token]['scope_closer']; + $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'Closer scope opener is not the arrow token'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'Closer scope closer is not the '.$expectedCloserType.' token'); + + }//end scopePositionTestHelper() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php new file mode 100644 index 000000000..8214ea1a9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php @@ -0,0 +1,555 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class BackfillMatchTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Test tokenization of match expressions. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * @param string $testContent The token content to look for. + * + * @dataProvider dataMatchExpression + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testMatchExpression($testMarker, $openerOffset, $closerOffset, $testContent='match') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_MATCH, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (code)'); + $this->assertSame('T_MATCH', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH (type)'); + + $this->scopeTestHelper($token, $openerOffset, $closerOffset); + $this->parenthesisTestHelper($token); + + }//end testMatchExpression() + + + /** + * Data provider. + * + * @see testMatchExpression() + * + * @return array> + */ + public static function dataMatchExpression() + { + return [ + 'simple_match' => [ + 'testMarker' => '/* testMatchSimple */', + 'openerOffset' => 6, + 'closerOffset' => 33, + ], + 'no_trailing_comma' => [ + 'testMarker' => '/* testMatchNoTrailingComma */', + 'openerOffset' => 6, + 'closerOffset' => 24, + ], + 'with_default_case' => [ + 'testMarker' => '/* testMatchWithDefault */', + 'openerOffset' => 6, + 'closerOffset' => 33, + ], + 'expression_in_condition' => [ + 'testMarker' => '/* testMatchExpressionInCondition */', + 'openerOffset' => 6, + 'closerOffset' => 77, + ], + 'multicase' => [ + 'testMarker' => '/* testMatchMultiCase */', + 'openerOffset' => 6, + 'closerOffset' => 40, + ], + 'multicase_trailing_comma_in_case' => [ + 'testMarker' => '/* testMatchMultiCaseTrailingCommaInCase */', + 'openerOffset' => 6, + 'closerOffset' => 47, + ], + 'in_closure_not_lowercase' => [ + 'testMarker' => '/* testMatchInClosureNotLowercase */', + 'openerOffset' => 6, + 'closerOffset' => 36, + 'testContent' => 'Match', + ], + 'in_arrow_function' => [ + 'testMarker' => '/* testMatchInArrowFunction */', + 'openerOffset' => 5, + 'closerOffset' => 36, + ], + 'arrow_function_in_match_no_trailing_comma' => [ + 'testMarker' => '/* testArrowFunctionInMatchNoTrailingComma */', + 'openerOffset' => 6, + 'closerOffset' => 44, + ], + 'in_function_call_param_not_lowercase' => [ + 'testMarker' => '/* testMatchInFunctionCallParamNotLowercase */', + 'openerOffset' => 8, + 'closerOffset' => 32, + 'testContent' => 'MATCH', + ], + 'in_method_call_param' => [ + 'testMarker' => '/* testMatchInMethodCallParam */', + 'openerOffset' => 5, + 'closerOffset' => 13, + ], + 'discard_result' => [ + 'testMarker' => '/* testMatchDiscardResult */', + 'openerOffset' => 6, + 'closerOffset' => 18, + ], + 'duplicate_conditions_and_comments' => [ + 'testMarker' => '/* testMatchWithDuplicateConditionsWithComments */', + 'openerOffset' => 12, + 'closerOffset' => 59, + ], + 'nested_match_outer' => [ + 'testMarker' => '/* testNestedMatchOuter */', + 'openerOffset' => 6, + 'closerOffset' => 33, + ], + 'nested_match_inner' => [ + 'testMarker' => '/* testNestedMatchInner */', + 'openerOffset' => 6, + 'closerOffset' => 14, + ], + 'ternary_condition' => [ + 'testMarker' => '/* testMatchInTernaryCondition */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'ternary_then' => [ + 'testMarker' => '/* testMatchInTernaryThen */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'ternary_else' => [ + 'testMarker' => '/* testMatchInTernaryElse */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'array_value' => [ + 'testMarker' => '/* testMatchInArrayValue */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'array_key' => [ + 'testMarker' => '/* testMatchInArrayKey */', + 'openerOffset' => 6, + 'closerOffset' => 21, + ], + 'returning_array' => [ + 'testMarker' => '/* testMatchreturningArray */', + 'openerOffset' => 6, + 'closerOffset' => 125, + ], + 'nested_in_switch_case_1' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase1 */', + 'openerOffset' => 6, + 'closerOffset' => 25, + ], + 'nested_in_switch_case_2' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase2 */', + 'openerOffset' => 6, + 'closerOffset' => 25, + ], + 'nested_in_switch_default' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchDefault */', + 'openerOffset' => 6, + 'closerOffset' => 25, + ], + 'match_with_nested_switch' => [ + 'testMarker' => '/* testMatchContainingSwitch */', + 'openerOffset' => 6, + 'closerOffset' => 180, + ], + 'no_cases' => [ + 'testMarker' => '/* testMatchNoCases */', + 'openerOffset' => 6, + 'closerOffset' => 7, + ], + 'multi_default' => [ + 'testMarker' => '/* testMatchMultiDefault */', + 'openerOffset' => 6, + 'closerOffset' => 40, + ], + ]; + + }//end dataMatchExpression() + + + /** + * Verify that "match" keywords which are not match control structures get tokenized as T_STRING + * and don't have the extra token array indexes. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotAMatchStructure + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotAMatchStructure($testMarker, $testContent='match') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + $next = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($token + 1), null, true); + if ($next !== false && $tokens[$next]['code'] === T_OPEN_PARENTHESIS) { + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set for opener after'); + } + + }//end testNotAMatchStructure() + + + /** + * Data provider. + * + * @see testNotAMatchStructure() + * + * @return array> + */ + public static function dataNotAMatchStructure() + { + return [ + 'static_method_call' => [ + 'testMarker' => '/* testNoMatchStaticMethodCall */', + ], + 'class_constant_access' => [ + 'testMarker' => '/* testNoMatchClassConstantAccess */', + 'testContent' => 'MATCH', + ], + 'class_constant_array_access' => [ + 'testMarker' => '/* testNoMatchClassConstantArrayAccessMixedCase */', + 'testContent' => 'Match', + ], + 'method_call' => [ + 'testMarker' => '/* testNoMatchMethodCall */', + ], + 'method_call_uppercase' => [ + 'testMarker' => '/* testNoMatchMethodCallUpper */', + 'testContent' => 'MATCH', + ], + 'property_access' => [ + 'testMarker' => '/* testNoMatchPropertyAccess */', + ], + 'namespaced_function_call' => [ + 'testMarker' => '/* testNoMatchNamespacedFunctionCall */', + ], + 'namespace_operator_function_call' => [ + 'testMarker' => '/* testNoMatchNamespaceOperatorFunctionCall */', + ], + 'interface_method_declaration' => [ + 'testMarker' => '/* testNoMatchInterfaceMethodDeclaration */', + ], + 'class_constant_declaration' => [ + 'testMarker' => '/* testNoMatchClassConstantDeclarationLower */', + ], + 'class_method_declaration' => [ + 'testMarker' => '/* testNoMatchClassMethodDeclaration */', + ], + 'property_assigment' => [ + 'testMarker' => '/* testNoMatchPropertyAssignment */', + ], + 'class_instantiation' => [ + 'testMarker' => '/* testNoMatchClassInstantiation */', + 'testContent' => 'Match', + ], + 'anon_class_method_declaration' => [ + 'testMarker' => '/* testNoMatchAnonClassMethodDeclaration */', + 'testContent' => 'maTCH', + ], + 'class_declaration' => [ + 'testMarker' => '/* testNoMatchClassDeclaration */', + 'testContent' => 'Match', + ], + 'interface_declaration' => [ + 'testMarker' => '/* testNoMatchInterfaceDeclaration */', + 'testContent' => 'Match', + ], + 'trait_declaration' => [ + 'testMarker' => '/* testNoMatchTraitDeclaration */', + 'testContent' => 'Match', + ], + 'constant_declaration' => [ + 'testMarker' => '/* testNoMatchConstantDeclaration */', + 'testContent' => 'MATCH', + ], + 'function_declaration' => [ + 'testMarker' => '/* testNoMatchFunctionDeclaration */', + ], + 'namespace_declaration' => [ + 'testMarker' => '/* testNoMatchNamespaceDeclaration */', + 'testContent' => 'Match', + ], + 'class_extends_declaration' => [ + 'testMarker' => '/* testNoMatchExtendedClassDeclaration */', + 'testContent' => 'Match', + ], + 'class_implements_declaration' => [ + 'testMarker' => '/* testNoMatchImplementedClassDeclaration */', + 'testContent' => 'Match', + ], + 'use_statement' => [ + 'testMarker' => '/* testNoMatchInUseStatement */', + 'testContent' => 'Match', + ], + 'unsupported_inline_control_structure' => [ + 'testMarker' => '/* testNoMatchMissingCurlies */', + ], + 'unsupported_alternative_syntax' => [ + 'testMarker' => '/* testNoMatchAlternativeSyntax */', + ], + 'live_coding' => [ + 'testMarker' => '/* testLiveCoding */', + ], + ]; + + }//end dataNotAMatchStructure() + + + /** + * Verify that the tokenization of switch structures is not affected by the backfill. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * + * @dataProvider dataSwitchExpression + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSwitchExpression($testMarker, $openerOffset, $closerOffset) + { + $token = $this->getTargetToken($testMarker, T_SWITCH); + + $this->scopeTestHelper($token, $openerOffset, $closerOffset); + $this->parenthesisTestHelper($token); + + }//end testSwitchExpression() + + + /** + * Data provider. + * + * @see testSwitchExpression() + * + * @return array> + */ + public static function dataSwitchExpression() + { + return [ + 'switch_containing_match' => [ + 'testMarker' => '/* testSwitchContainingMatch */', + 'openerOffset' => 6, + 'closerOffset' => 174, + ], + 'match_containing_switch_1' => [ + 'testMarker' => '/* testSwitchNestedInMatch1 */', + 'openerOffset' => 5, + 'closerOffset' => 63, + ], + 'match_containing_switch_2' => [ + 'testMarker' => '/* testSwitchNestedInMatch2 */', + 'openerOffset' => 5, + 'closerOffset' => 63, + ], + ]; + + }//end dataSwitchExpression() + + + /** + * Verify that the tokenization of a switch case/default structure containing a match structure + * or contained *in* a match structure is not affected by the backfill. + * + * @param string $testMarker The comment prefacing the target token. + * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. + * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. + * + * @dataProvider dataSwitchCaseVersusMatch + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSwitchCaseVersusMatch($testMarker, $openerOffset, $closerOffset) + { + $token = $this->getTargetToken($testMarker, [T_CASE, T_DEFAULT]); + + $this->scopeTestHelper($token, $openerOffset, $closerOffset); + + }//end testSwitchCaseVersusMatch() + + + /** + * Data provider. + * + * @see testSwitchCaseVersusMatch() + * + * @return array> + */ + public static function dataSwitchCaseVersusMatch() + { + return [ + 'switch_with_nested_match_case_1' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase1 */', + 'openerOffset' => 3, + 'closerOffset' => 55, + ], + 'switch_with_nested_match_case_2' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase2 */', + 'openerOffset' => 4, + 'closerOffset' => 21, + ], + 'switch_with_nested_match_default_case' => [ + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 38, + ], + 'match_with_nested_switch_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'openerOffset' => 1, + 'closerOffset' => 18, + ], + 'match_with_nested_switch_default_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 20, + ], + ]; + + }//end dataSwitchCaseVersusMatch() + + + /** + * Helper function to verify that all scope related array indexes for a control structure + * are set correctly. + * + * @param int $token The control structure token to check. + * @param int $openerOffset The expected offset of the scope opener in relation to + * the control structure token. + * @param int $closerOffset The expected offset of the scope closer in relation to + * the control structure token. + * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. + * This should be set to "true" when testing nested arrow functions, + * where the "inner" arrow function shares a scope closer with the + * "outer" arrow function, as the 'scope_condition' for the scope closer + * of the "inner" arrow function will point to the "outer" arrow function. + * + * @return void + */ + private function scopeTestHelper($token, $openerOffset, $closerOffset, $skipScopeCloserCheck=false) + { + $tokens = $this->phpcsFile->getTokens(); + $tokenArray = $tokens[$token]; + $tokenType = $tokenArray['type']; + $expectedScopeOpener = ($token + $openerOffset); + $expectedScopeCloser = ($token + $closerOffset); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); + $this->assertSame($token, $tokenArray['scope_condition'], 'Scope condition is not the '.$tokenType.' token'); + $this->assertSame($expectedScopeOpener, $tokenArray['scope_opener'], 'Scope opener of the '.$tokenType.' token incorrect'); + $this->assertSame($expectedScopeCloser, $tokenArray['scope_closer'], 'Scope closer of the '.$tokenType.' token incorrect'); + + $opener = $tokenArray['scope_opener']; + $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); + $this->assertSame($token, $tokens[$opener]['scope_condition'], 'Opener scope condition is not the '.$tokenType.' token'); + $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], $tokenType.' opener scope opener token incorrect'); + $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], $tokenType.' opener scope closer token incorrect'); + + $closer = $tokenArray['scope_closer']; + $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); + if ($skipScopeCloserCheck === false) { + $this->assertSame($token, $tokens[$closer]['scope_condition'], 'Closer scope condition is not the '.$tokenType.' token'); + } + + $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], $tokenType.' closer scope opener token incorrect'); + $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], $tokenType.' closer scope closer token incorrect'); + + if (($opener + 1) !== $closer) { + for ($i = ($opener + 1); $i < $closer; $i++) { + $this->assertArrayHasKey( + $token, + $tokens[$i]['conditions'], + $tokenType.' condition not added for token belonging to the '.$tokenType.' structure' + ); + } + } + + }//end scopeTestHelper() + + + /** + * Helper function to verify that all parenthesis related array indexes for a control structure + * token are set correctly. + * + * @param int $token The position of the control structure token. + * + * @return void + */ + private function parenthesisTestHelper($token) + { + $tokens = $this->phpcsFile->getTokens(); + $tokenArray = $tokens[$token]; + $tokenType = $tokenArray['type']; + + $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); + $this->assertSame($token, $tokenArray['parenthesis_owner'], 'Parenthesis owner is not the '.$tokenType.' token'); + + $opener = $tokenArray['parenthesis_opener']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener], 'Opening parenthesis owner is not set'); + $this->assertSame($token, $tokens[$opener]['parenthesis_owner'], 'Opening parenthesis owner is not the '.$tokenType.' token'); + + $closer = $tokenArray['parenthesis_closer']; + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer], 'Closing parenthesis owner is not set'); + $this->assertSame($token, $tokens[$closer]['parenthesis_owner'], 'Closing parenthesis owner is not the '.$tokenType.' token'); + + }//end parenthesisTestHelper() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.php new file mode 100644 index 000000000..92bc59bcc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.php @@ -0,0 +1,402 @@ + + * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class BackfillNumericSeparatorTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that numbers using numeric separators are tokenized correctly. + * + * @param string $marker The comment which prefaces the target token in the test file. + * @param string $type The expected token type. + * @param string $value The expected token content. + * + * @dataProvider dataTestBackfill + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testBackfill($marker, $type, $value) + { + $tokens = $this->phpcsFile->getTokens(); + $number = $this->getTargetToken($marker, [T_LNUMBER, T_DNUMBER]); + $tokenArray = $tokens[$number]; + + $this->assertSame(constant($type), $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not '.$type.' (code)'); + $this->assertSame($type, $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not '.$type.' (type)'); + $this->assertSame($value, $tokenArray['content']); + + }//end testBackfill() + + + /** + * Data provider. + * + * @see testBackfill() + * + * @return array> + */ + public static function dataTestBackfill() + { + $testHexType = 'T_LNUMBER'; + if (PHP_INT_MAX < 0xCAFEF00D) { + $testHexType = 'T_DNUMBER'; + } + + $testHexMultipleType = 'T_LNUMBER'; + if (PHP_INT_MAX < 0x42726F776E) { + $testHexMultipleType = 'T_DNUMBER'; + } + + $testIntMoreThanMaxType = 'T_LNUMBER'; + if (PHP_INT_MAX < 10223372036854775807) { + $testIntMoreThanMaxType = 'T_DNUMBER'; + } + + return [ + 'decimal integer' => [ + 'marker' => '/* testSimpleLNumber */', + 'type' => 'T_LNUMBER', + 'value' => '1_000_000_000', + ], + 'float' => [ + 'marker' => '/* testSimpleDNumber */', + 'type' => 'T_DNUMBER', + 'value' => '107_925_284.88', + ], + 'float, scientific notation, negative exponent with sigh' => [ + 'marker' => '/* testFloat */', + 'type' => 'T_DNUMBER', + 'value' => '6.674_083e-11', + ], + 'float, scientific notation, positive exponent with sign' => [ + 'marker' => '/* testFloat2 */', + 'type' => 'T_DNUMBER', + 'value' => '6.674_083e+11', + ], + 'float, scientific notation, positive exponent without sign' => [ + 'marker' => '/* testFloat3 */', + 'type' => 'T_DNUMBER', + 'value' => '1_2.3_4e1_23', + ], + 'hexidecimal integer/float' => [ + 'marker' => '/* testHex */', + 'type' => $testHexType, + 'value' => '0xCAFE_F00D', + ], + 'hexidecimal integer/float with multiple underscores' => [ + 'marker' => '/* testHexMultiple */', + 'type' => $testHexMultipleType, + 'value' => '0x42_72_6F_77_6E', + ], + 'hexidecimal integer' => [ + 'marker' => '/* testHexInt */', + 'type' => 'T_LNUMBER', + 'value' => '0x42_72_6F', + ], + 'binary integer' => [ + 'marker' => '/* testBinary */', + 'type' => 'T_LNUMBER', + 'value' => '0b0101_1111', + ], + 'octal integer' => [ + 'marker' => '/* testOctal */', + 'type' => 'T_LNUMBER', + 'value' => '0137_041', + ], + 'octal integer using explicit octal notation' => [ + 'marker' => '/* testExplicitOctal */', + 'type' => 'T_LNUMBER', + 'value' => '0o137_041', + ], + 'octal integer using explicit octal notation with capital O' => [ + 'marker' => '/* testExplicitOctalCapitalised */', + 'type' => 'T_LNUMBER', + 'value' => '0O137_041', + ], + 'integer more than PHP_INT_MAX becomes a float' => [ + 'marker' => '/* testIntMoreThanMax */', + 'type' => $testIntMoreThanMaxType, + 'value' => '10_223_372_036_854_775_807', + ], + ]; + + }//end dataTestBackfill() + + + /** + * Test that numbers using numeric separators which are considered parse errors and/or + * which aren't relevant to the backfill, do not incorrectly trigger the backfill anyway. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokens The token type and content of the expected token sequence. + * + * @dataProvider dataNoBackfill + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNoBackfill($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $number = $this->getTargetToken($testMarker, [T_LNUMBER, T_DNUMBER]); + + foreach ($expectedTokens as $key => $expectedToken) { + $i = ($number + $key); + $this->assertSame( + $expectedToken['code'], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.Tokens::tokenName($expectedToken['code']) + ); + $this->assertSame($expectedToken['content'], $tokens[$i]['content']); + } + + }//end testNoBackfill() + + + /** + * Data provider. + * + * @see testBackfill() + * + * @return array>>> + */ + public static function dataNoBackfill() + { + return [ + 'invalid: trailing underscore' => [ + 'testMarker' => '/* testInvalid1 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '100', + ], + [ + 'code' => T_STRING, + 'content' => '_', + ], + ], + ], + 'invalid: two consecutive underscores' => [ + 'testMarker' => '/* testInvalid2 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => '__1', + ], + ], + ], + 'invalid: underscore directly before decimal point' => [ + 'testMarker' => '/* testInvalid3 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => '_', + ], + [ + 'code' => T_DNUMBER, + 'content' => '.0', + ], + ], + ], + 'invalid: underscore directly after decimal point' => [ + 'testMarker' => '/* testInvalid4 */', + 'expectedTokens' => [ + [ + 'code' => T_DNUMBER, + 'content' => '1.', + ], + [ + 'code' => T_STRING, + 'content' => '_0', + ], + ], + ], + 'invalid: hex int - underscore directly after x' => [ + 'testMarker' => '/* testInvalid5 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'x_123', + ], + ], + ], + 'invalid: binary int - underscore directly after b' => [ + 'testMarker' => '/* testInvalid6 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'b_101', + ], + ], + ], + 'invalid: scientific float - underscore directly before e' => [ + 'testMarker' => '/* testInvalid7 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => '_e2', + ], + ], + ], + 'invalid: scientific float - underscore directly after e' => [ + 'testMarker' => '/* testInvalid8 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '1', + ], + [ + 'code' => T_STRING, + 'content' => 'e_2', + ], + ], + ], + 'invalid: space between parts of the number' => [ + 'testMarker' => '/* testInvalid9 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '107_925_284', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_DNUMBER, + 'content' => '.88', + ], + ], + ], + 'invalid: comment within the number' => [ + 'testMarker' => '/* testInvalid10 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '107_925_284', + ], + [ + 'code' => T_COMMENT, + 'content' => '/*comment*/', + ], + [ + 'code' => T_DNUMBER, + 'content' => '.88', + ], + ], + ], + 'invalid: explicit octal int - underscore directly after o' => [ + 'testMarker' => '/* testInvalid11 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'o_137', + ], + ], + ], + 'invalid: explicit octal int - underscore directly after capital O' => [ + 'testMarker' => '/* testInvalid12 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '0', + ], + [ + 'code' => T_STRING, + 'content' => 'O_41', + ], + ], + ], + 'calculations should be untouched - int - int' => [ + 'testMarker' => '/* testCalc1 */', + 'expectedTokens' => [ + [ + 'code' => T_LNUMBER, + 'content' => '667_083', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_MINUS, + 'content' => '-', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_LNUMBER, + 'content' => '11', + ], + ], + ], + 'calculations should be untouched - scientific float + int' => [ + 'testMarker' => '/* test Calc2 */', + 'expectedTokens' => [ + [ + 'code' => T_DNUMBER, + 'content' => '6.674_08e3', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_PLUS, + 'content' => '+', + ], + [ + 'code' => T_WHITESPACE, + 'content' => ' ', + ], + [ + 'code' => T_LNUMBER, + 'content' => '11', + ], + ], + ], + ]; + + }//end dataNoBackfill() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc new file mode 100644 index 000000000..eb36e3870 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc @@ -0,0 +1,156 @@ +readonly = 'foo'; + + /* testReadonlyPropertyInTernaryOperator */ + $isReadonly = $this->readonly ? true : false; + } +} + +/* testReadonlyUsedAsFunctionName */ +function readonly() {} + +/* testReadonlyUsedAsFunctionNameWithReturnByRef */ +function &readonly() {} + +/* testReadonlyUsedAsNamespaceName */ +namespace Readonly; +/* testReadonlyUsedAsPartOfNamespaceName */ +namespace My\Readonly\Collection; +/* testReadonlyAsFunctionCall */ +$var = readonly($a, $b); +/* testReadonlyAsNamespacedFunctionCall */ +$var = My\NS\readonly($a, $b); +/* testReadonlyAsNamespaceRelativeFunctionCall */ +$var = namespace\ReadOnly($a, $b); +/* testReadonlyAsMethodCall */ +$var = $obj->readonly($a, $b); +/* testReadonlyAsNullsafeMethodCall */ +$var = $obj?->readOnly($a, $b); +/* testReadonlyAsStaticMethodCallWithSpace */ +$var = ClassName::readonly ($a, $b); +/* testClassConstantFetchWithReadonlyAsConstantName */ +echo ClassName::READONLY; + +/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */ +$var = readonly /* comment */ (); + +// These test cases are inspired by +// https://github.com/php/php-src/commit/08b75395838b4b42a41e3c70684fa6c6b113eee0 +class ReadonlyWithDisjunctiveNormalForm +{ + /* testReadonlyPropertyDNFTypeUnqualified */ + readonly (B&C)|A $h; + + /* testReadonlyPropertyDNFTypeFullyQualified */ + public readonly (\Fully\Qualified\B&\Full\C)|\Foo\Bar $j; + + /* testReadonlyPropertyDNFTypePartiallyQualified */ + protected readonly (Partially\Qualified&C)|A $l; + + /* testReadonlyPropertyDNFTypeRelativeName */ + private readonly (namespace\Relative&C)|A $n; + + /* testReadonlyPropertyDNFTypeMultipleSets */ + private readonly (A&C)|(B&C)|(C&D) $m; + + /* testReadonlyPropertyDNFTypeWithArray */ + private readonly (B & C)|array $o; + + /* testReadonlyPropertyDNFTypeWithSpacesAndComments */ + private readonly ( B & C /*something*/) | A $q; + + public function __construct( + /* testReadonlyConstructorPropertyPromotionWithDNF */ + private readonly (B&C)|A $b1, + /* testReadonlyConstructorPropertyPromotionWithDNFAndReference */ + readonly (B&C)|A &$b2, + ) {} + + /* testReadonlyUsedAsMethodNameWithDNFParam */ + public function readonly (A&B $param): void {} +} + +/* testReadonlyAnonClassWithParens */ +$anon = new readonly class() {}; + +/* testReadonlyAnonClassWithoutParens */ +$anon = new Readonly class {}; + +/* testReadonlyAnonClassWithCommentsAndWhitespace */ +$anon = new +// comment +READONLY +// phpcs:ignore Stnd.Cat.Sniff +class {}; + +/* testParseErrorLiveCoding */ +// This must be the last test in the file. +readonly diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php new file mode 100644 index 000000000..89dc3e19d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php @@ -0,0 +1,271 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillReadonlyTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the "readonly" keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent Optional. The token content to look for. + * Defaults to lowercase "readonly". + * + * @dataProvider dataReadonly + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testReadonly($testMarker, $testContent='readonly') + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_READONLY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_READONLY (code)'); + $this->assertSame('T_READONLY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_READONLY (type)'); + + }//end testReadonly() + + + /** + * Data provider. + * + * @see testReadonly() + * + * @return array> + */ + public static function dataReadonly() + { + return [ + 'property declaration, no visibility' => [ + 'testMarker' => '/* testReadonlyProperty */', + ], + 'property declaration, var keyword before' => [ + 'testMarker' => '/* testVarReadonlyProperty */', + ], + 'property declaration, var keyword after' => [ + 'testMarker' => '/* testReadonlyVarProperty */', + ], + 'property declaration, static before' => [ + 'testMarker' => '/* testStaticReadonlyProperty */', + ], + 'property declaration, static after' => [ + 'testMarker' => '/* testReadonlyStaticProperty */', + ], + 'constant declaration, with visibility' => [ + 'testMarker' => '/* testConstReadonlyProperty */', + ], + 'property declaration, missing type' => [ + 'testMarker' => '/* testReadonlyPropertyWithoutType */', + ], + 'property declaration, public before' => [ + 'testMarker' => '/* testPublicReadonlyProperty */', + ], + 'property declaration, protected before' => [ + 'testMarker' => '/* testProtectedReadonlyProperty */', + ], + 'property declaration, private before' => [ + 'testMarker' => '/* testPrivateReadonlyProperty */', + ], + 'property declaration, public after' => [ + 'testMarker' => '/* testPublicReadonlyPropertyWithReadonlyFirst */', + ], + 'property declaration, protected after' => [ + 'testMarker' => '/* testProtectedReadonlyPropertyWithReadonlyFirst */', + ], + 'property declaration, private after' => [ + 'testMarker' => '/* testPrivateReadonlyPropertyWithReadonlyFirst */', + ], + 'property declaration, private before, comments in declaration' => [ + 'testMarker' => '/* testReadonlyWithCommentsInDeclaration */', + ], + 'property declaration, private before, nullable type' => [ + 'testMarker' => '/* testReadonlyWithNullableProperty */', + ], + 'property declaration, private before, union type, null first' => [ + 'testMarker' => '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullFirst */', + ], + 'property declaration, private before, union type, null last' => [ + 'testMarker' => '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullLast */', + ], + 'property declaration, private before, array type' => [ + 'testMarker' => '/* testReadonlyPropertyWithArrayTypeHint */', + ], + 'property declaration, private before, self type' => [ + 'testMarker' => '/* testReadonlyPropertyWithSelfTypeHint */', + ], + 'property declaration, private before, parent type' => [ + 'testMarker' => '/* testReadonlyPropertyWithParentTypeHint */', + ], + 'property declaration, private before, FQN type' => [ + 'testMarker' => '/* testReadonlyPropertyWithFullyQualifiedTypeHint */', + ], + 'property declaration, public before, mixed case' => [ + 'testMarker' => '/* testReadonlyIsCaseInsensitive */', + 'testContent' => 'ReAdOnLy', + ], + 'property declaration, constructor property promotion' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotion */', + ], + 'property declaration, constructor property promotion with reference, mixed case' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithReference */', + 'testContent' => 'ReadOnly', + ], + 'property declaration, in anonymous class' => [ + 'testMarker' => '/* testReadonlyPropertyInAnonymousClass */', + ], + 'property declaration, no visibility, DNF type, unqualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeUnqualified */', + ], + 'property declaration, public before, DNF type, fully qualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeFullyQualified */', + ], + 'property declaration, protected before, DNF type, partially qualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypePartiallyQualified */', + ], + 'property declaration, private before, DNF type, namespace relative name' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeRelativeName */', + ], + 'property declaration, private before, DNF type, multiple sets' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeMultipleSets */', + ], + 'property declaration, private before, DNF type, union with array' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeWithArray */', + ], + 'property declaration, private before, DNF type, with spaces and comment' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeWithSpacesAndComments */', + ], + 'property declaration, constructor property promotion, DNF type' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithDNF */', + ], + 'property declaration, constructor property promotion, DNF type and reference' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithDNFAndReference */', + ], + 'anon class declaration, with parentheses' => [ + 'testMarker' => '/* testReadonlyAnonClassWithParens */', + ], + 'anon class declaration, without parentheses' => [ + 'testMarker' => '/* testReadonlyAnonClassWithoutParens */', + 'testContent' => 'Readonly', + ], + 'anon class declaration, with comments and whitespace' => [ + 'testMarker' => '/* testReadonlyAnonClassWithCommentsAndWhitespace */', + 'testContent' => 'READONLY', + ], + 'live coding / parse error' => [ + 'testMarker' => '/* testParseErrorLiveCoding */', + ], + ]; + + }//end dataReadonly() + + + /** + * Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testContent Optional. The token content to look for. + * Defaults to lowercase "readonly". + * + * @dataProvider dataNotReadonly + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotReadonly($testMarker, $testContent='readonly') + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotReadonly() + + + /** + * Data provider. + * + * @see testNotReadonly() + * + * @return array> + */ + public static function dataNotReadonly() + { + return [ + 'name of a constant, context: declaration using "const" keyword, uppercase' => [ + 'testMarker' => '/* testReadonlyUsedAsClassConstantName */', + 'testContent' => 'READONLY', + ], + 'name of a method, context: declaration' => [ + 'testMarker' => '/* testReadonlyUsedAsMethodName */', + ], + 'name of a property, context: property access' => [ + 'testMarker' => '/* testReadonlyUsedAsPropertyName */', + ], + 'name of a property, context: property access in ternary' => [ + 'testMarker' => '/* testReadonlyPropertyInTernaryOperator */', + ], + 'name of a function, context: declaration' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionName */', + ], + 'name of a function, context: declaration with return by ref' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionNameWithReturnByRef */', + ], + 'name of namespace, context: declaration, mixed case' => [ + 'testMarker' => '/* testReadonlyUsedAsNamespaceName */', + 'testContent' => 'Readonly', + ], + 'partial name of namespace, context: declaration, mixed case' => [ + 'testMarker' => '/* testReadonlyUsedAsPartOfNamespaceName */', + 'testContent' => 'Readonly', + ], + 'name of a function, context: call' => [ + 'testMarker' => '/* testReadonlyAsFunctionCall */', + ], + 'name of a namespaced function, context: partially qualified call' => [ + 'testMarker' => '/* testReadonlyAsNamespacedFunctionCall */', + ], + 'name of a function, context: namespace relative call, mixed case' => [ + 'testMarker' => '/* testReadonlyAsNamespaceRelativeFunctionCall */', + 'testContent' => 'ReadOnly', + ], + 'name of a method, context: method call on object' => [ + 'testMarker' => '/* testReadonlyAsMethodCall */', + ], + 'name of a method, context: nullsafe method call on object' => [ + 'testMarker' => '/* testReadonlyAsNullsafeMethodCall */', + 'testContent' => 'readOnly', + ], + 'name of a method, context: static method call with space after' => [ + 'testMarker' => '/* testReadonlyAsStaticMethodCallWithSpace */', + ], + 'name of a constant, context: constant access - uppercase' => [ + 'testMarker' => '/* testClassConstantFetchWithReadonlyAsConstantName */', + 'testContent' => 'READONLY', + ], + 'name of a function, context: call with space and comment between keyword and parens' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */', + ], + 'name of a method, context: declaration with DNF parameter' => [ + 'testMarker' => '/* testReadonlyUsedAsMethodNameWithDNFParam */', + ], + ]; + + }//end dataNotReadonly() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc new file mode 100644 index 000000000..c2c4508e4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc @@ -0,0 +1,192 @@ + $param | $int; + +/* testTypeUnionArrowReturnType */ +$arrowWithReturnType = fn ($param) : int|null => $param * 10; + +/* testBitwiseOrInArrayKey */ +$array = array( + A | B => /* testBitwiseOrInArrayValue */ B | C +); + +/* testBitwiseOrInShortArrayKey */ +$array = [ + A | B => /* testBitwiseOrInShortArrayValue */ B | C +]; + +/* testBitwiseOrTryCatch */ +try { +} catch ( ExceptionA | ExceptionB $e ) { +} + +/* testBitwiseOrNonArrowFnFunctionCall */ +$obj->fn($something | $else); + +/* testTypeUnionNonArrowFunctionDeclaration */ +function &fn(int|false $something) {} + +/* testTypeUnionPHP82TrueFirst */ +function trueTypeParam(true|null $param) {} + +/* testTypeUnionPHP82TrueMiddle */ +function trueTypeReturn($param): array|true|null {} + +/* testTypeUnionPHP82TrueLast */ +$closure = function ($param): array|true {} + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +return function( type| diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php new file mode 100644 index 000000000..ee1ff84f2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php @@ -0,0 +1,163 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BitwiseOrTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that non-union type bitwise or tokens are still tokenized as bitwise or. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataBitwiseOr + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBitwiseOr($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_BITWISE_OR, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_OR (type)'); + + }//end testBitwiseOr() + + + /** + * Data provider. + * + * @see testBitwiseOr() + * + * @return array> + */ + public static function dataBitwiseOr() + { + return [ + 'in simple assignment 1' => ['/* testBitwiseOr1 */'], + 'in simple assignment 2' => ['/* testBitwiseOr2 */'], + 'in OO constant default value' => ['/* testBitwiseOrOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseOrPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseOrParamDefaultValue */'], + 'in return statement' => ['/* testBitwiseOr3 */'], + 'in closure parameter default value' => ['/* testBitwiseOrClosureParamDefault */'], + 'in OO constant default value DNF-like' => ['/* testBitwiseOrOOConstDefaultValueDNF */'], + 'in property default value DNF-like' => ['/* testBitwiseOrPropertyDefaultValueDNF */'], + 'in method parameter default value DNF-like' => ['/* testBitwiseOrParamDefaultValueDNF */'], + 'in arrow function parameter default value' => ['/* testBitwiseOrArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseOrArrowExpression */'], + 'in long array key' => ['/* testBitwiseOrInArrayKey */'], + 'in long array value' => ['/* testBitwiseOrInArrayValue */'], + 'in short array key' => ['/* testBitwiseOrInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseOrInShortArrayValue */'], + 'in catch condition' => ['/* testBitwiseOrTryCatch */'], + 'in parameter in function call' => ['/* testBitwiseOrNonArrowFnFunctionCall */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], + ]; + + }//end dataBitwiseOr() + + + /** + * Test that bitwise or tokens when used as part of a union type are tokenized as `T_TYPE_UNION`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataTypeUnion + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTypeUnion($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_TYPE_UNION, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_UNION (code)'); + $this->assertSame('T_TYPE_UNION', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_UNION (type)'); + + }//end testTypeUnion() + + + /** + * Data provider. + * + * @see testTypeUnion() + * + * @return array> + */ + public static function dataTypeUnion() + { + return [ + 'type for OO constant' => ['/* testTypeUnionOOConstSimple */'], + 'type for OO constant, reversed modifier order' => ['/* testTypeUnionOOConstReverseModifierOrder */'], + 'type for OO constant, first of multi-union' => ['/* testTypeUnionOOConstMulti1 */'], + 'type for OO constant, middle of multi-union + comments' => ['/* testTypeUnionOOConstMulti2 */'], + 'type for OO constant, last of multi-union' => ['/* testTypeUnionOOConstMulti3 */'], + 'type for OO constant, using namespace relative names' => ['/* testTypeUnionOOConstNamespaceRelative */'], + 'type for OO constant, using partially qualified names' => ['/* testTypeUnionOOConstPartiallyQualified */'], + 'type for OO constant, using fully qualified names' => ['/* testTypeUnionOOConstFullyQualified */'], + 'type for static property' => ['/* testTypeUnionPropertySimple */'], + 'type for static property, reversed modifier order' => ['/* testTypeUnionPropertyReverseModifierOrder */'], + 'type for property, first of multi-union' => ['/* testTypeUnionPropertyMulti1 */'], + 'type for property, middle of multi-union, also comments' => ['/* testTypeUnionPropertyMulti2 */'], + 'type for property, last of multi-union' => ['/* testTypeUnionPropertyMulti3 */'], + 'type for property using namespace relative names' => ['/* testTypeUnionPropertyNamespaceRelative */'], + 'type for property using partially qualified names' => ['/* testTypeUnionPropertyPartiallyQualified */'], + 'type for property using fully qualified names' => ['/* testTypeUnionPropertyFullyQualified */'], + 'type for readonly property' => ['/* testTypeUnionPropertyWithReadOnlyKeyword */'], + 'type for static readonly property' => ['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'], + 'type for readonly property using var keyword' => ['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'], + 'type for readonly property, reversed modifier order' => ['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'], + 'type for readonly property, no visibility' => ['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'], + 'type for static property, no visibility' => ['/* testTypeUnionPropertyWithOnlyStaticKeyword */'], + 'type for final property, no visibility' => ['/* testTypeUnionWithPHP84FinalKeyword */'], + 'type for final property, reversed modifier order' => ['/* testTypeUnionWithPHP84FinalKeywordFirst */'], + 'type for final property, no visibility, FQN type' => ['/* testTypeUnionWithPHP84FinalKeywordAndFQN */'], + 'type for method parameter' => ['/* testTypeUnionParam1 */'], + 'type for method parameter, first in multi-union' => ['/* testTypeUnionParam2 */'], + 'type for method parameter, last in multi-union' => ['/* testTypeUnionParam3 */'], + 'type for method parameter with namespace relative names' => ['/* testTypeUnionParamNamespaceRelative */'], + 'type for method parameter with partially qualified names' => ['/* testTypeUnionParamPartiallyQualified */'], + 'type for method parameter with fully qualified names' => ['/* testTypeUnionParamFullyQualified */'], + 'type for property in constructor property promotion' => ['/* testTypeUnionConstructorPropertyPromotion */'], + 'return type for method' => ['/* testTypeUnionReturnType */'], + 'return type for method, first of multi-union' => ['/* testTypeUnionAbstractMethodReturnType1 */'], + 'return type for method, last of multi-union' => ['/* testTypeUnionAbstractMethodReturnType2 */'], + 'return type for method with namespace relative names' => ['/* testTypeUnionReturnTypeNamespaceRelative */'], + 'return type for method with partially qualified names' => ['/* testTypeUnionReturnPartiallyQualified */'], + 'return type for method with fully qualified names' => ['/* testTypeUnionReturnFullyQualified */'], + 'type for function parameter with reference' => ['/* testTypeUnionWithReference */'], + 'type for function parameter with spread operator' => ['/* testTypeUnionWithSpreadOperator */'], + 'DNF type for OO constant, union before DNF' => ['/* testTypeUnionConstantTypeUnionBeforeDNF */'], + 'DNF type for property, union after DNF' => ['/* testTypeUnionPropertyTypeUnionAfterDNF */'], + 'DNF type for function param, union before and after DNF' => ['/* testTypeUnionParamUnionBeforeAndAfterDNF */'], + 'DNF type for function return, union after DNF with null' => ['/* testTypeUnionReturnTypeUnionAfterDNF */'], + 'type for closure parameter with illegal nullable' => ['/* testTypeUnionClosureParamIllegalNullable */'], + 'return type for closure' => ['/* testTypeUnionClosureReturn */'], + 'type for arrow function parameter' => ['/* testTypeUnionArrowParam */'], + 'return type for arrow function' => ['/* testTypeUnionArrowReturnType */'], + 'type for function parameter, return by ref' => ['/* testTypeUnionNonArrowFunctionDeclaration */'], + 'type for function param with true type first' => ['/* testTypeUnionPHP82TrueFirst */'], + 'type for function param with true type middle' => ['/* testTypeUnionPHP82TrueMiddle */'], + 'type for function param with true type last' => ['/* testTypeUnionPHP82TrueLast */'], + ]; + + }//end dataTypeUnion() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc similarity index 83% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc index 82fe56438..2825f26e5 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc @@ -1,227 +1,244 @@ - 'a', - 2 => 'b', - /* testMatchDefaultIsKeyword */ default => 'default', -}; - -$closure = /* testFnIsKeyword */ fn () => 'string'; - -function () { - /* testYieldIsKeyword */ yield $f; - /* testYieldFromIsKeyword */ yield from someFunction(); -}; - -/* testDeclareIsKeyword */ declare(ticks=1): -/* testEndDeclareIsKeyword */ enddeclare; - -if (true /* testAndIsKeyword */ and false /* testOrIsKeyword */ or null /* testXorIsKeyword */ xor 0) { - -} - -$anonymousClass = new /* testAnonymousClassIsKeyword */ class {}; -$anonymousClass2 = new class /* testExtendsInAnonymousClassIsKeyword */ extends SomeParent {}; -$anonymousClass3 = new class /* testImplementsInAnonymousClassIsKeyword */ implements SomeInterface {}; - -$instantiated1 = new /* testClassInstantiationParentIsKeyword */ parent(); -$instantiated2 = new /* testClassInstantiationSelfIsKeyword */ SELF; -$instantiated3 = new /* testClassInstantiationStaticIsKeyword */ static($param); - -class Foo extends /* testNamespaceInNameIsKeyword */ namespace\Exception -{} - -function /* testKeywordAfterFunctionShouldBeString */ eval() {} -function /* testKeywordAfterFunctionByRefShouldBeString */ &switch() {} + 'a', + 2 => 'b', + /* testMatchDefaultIsKeyword */ default => 'default', +}; + +$closure = /* testFnIsKeyword */ fn () => 'string'; + +function () { + /* testYieldIsKeyword */ yield $f; + /* testYieldFromIsKeyword */ yield from someFunction(); +}; + +/* testDeclareIsKeyword */ declare(ticks=1): +/* testEndDeclareIsKeyword */ enddeclare; + +if (true /* testAndIsKeyword */ and false /* testOrIsKeyword */ or null /* testXorIsKeyword */ xor 0) { + +} + +$anonymousClass = new /* testAnonymousClassIsKeyword */ class {}; +$anonymousClass2 = new class /* testExtendsInAnonymousClassIsKeyword */ extends SomeParent {}; +$anonymousClass3 = new class /* testImplementsInAnonymousClassIsKeyword */ implements SomeInterface {}; + +$instantiated = new /* testClassInstantiationStaticIsKeyword */ static($param); + +class Foo extends /* testNamespaceInNameIsKeyword */ namespace\Exception +{} + +function /* testKeywordAfterFunctionShouldBeString */ eval() {} +function /* testKeywordAfterFunctionByRefShouldBeString */ &switch() {} + +function /* testKeywordStaticAfterFunctionByRefShouldBeString */ &static() {} + +/* testKeywordAsFunctionCallNameShouldBeStringStatic */ static(); +$obj-> /* testKeywordAsMethodCallNameShouldBeStringStatic */ static(); + +$function = /* testStaticIsKeywordBeforeClosure */ static function(/* testStaticIsKeywordWhenParamType */ static $param) {}; +$arrow = /* testStaticIsKeywordBeforeArrow */ static fn(): /* testStaticIsKeywordWhenReturnType */ static => 10; + +/* testKeywordAsFunctionCallNameShouldBeStringStaticDNFLookaLike */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + +class DNF { + public /* testStaticIsKeywordPropertyModifierBeforeDNF */ static (DN&F)|null $dnfProp; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php new file mode 100644 index 000000000..a8d746ae9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php @@ -0,0 +1,548 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class ContextSensitiveKeywordsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that context sensitive keyword is tokenized as string when it should be string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataStrings + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testStrings($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_STRING])); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testStrings() + + + /** + * Data provider. + * + * @see testStrings() + * + * @return array> + */ + public static function dataStrings() + { + return [ + 'constant declaration: abstract' => ['/* testAbstract */'], + 'constant declaration: array' => ['/* testArray */'], + 'constant declaration: as' => ['/* testAs */'], + 'constant declaration: break' => ['/* testBreak */'], + 'constant declaration: callable' => ['/* testCallable */'], + 'constant declaration: case' => ['/* testCase */'], + 'constant declaration: catch' => ['/* testCatch */'], + 'constant declaration: class' => ['/* testClass */'], + 'constant declaration: clone' => ['/* testClone */'], + 'constant declaration: const' => ['/* testConst */'], + 'constant declaration: continue' => ['/* testContinue */'], + 'constant declaration: declare' => ['/* testDeclare */'], + 'constant declaration: default' => ['/* testDefault */'], + 'constant declaration: do' => ['/* testDo */'], + 'constant declaration: echo' => ['/* testEcho */'], + 'constant declaration: else' => ['/* testElse */'], + 'constant declaration: elseif' => ['/* testElseIf */'], + 'constant declaration: empty' => ['/* testEmpty */'], + 'constant declaration: enddeclare' => ['/* testEndDeclare */'], + 'constant declaration: endfor' => ['/* testEndFor */'], + 'constant declaration: endforeach' => ['/* testEndForeach */'], + 'constant declaration: endif' => ['/* testEndIf */'], + 'constant declaration: endswitch' => ['/* testEndSwitch */'], + 'constant declaration: endwhile' => ['/* testEndWhile */'], + 'constant declaration: enum' => ['/* testEnum */'], + 'constant declaration: eval' => ['/* testEval */'], + 'constant declaration: exit' => ['/* testExit */'], + 'constant declaration: extends' => ['/* testExtends */'], + 'constant declaration: final' => ['/* testFinal */'], + 'constant declaration: finally' => ['/* testFinally */'], + 'constant declaration: fn' => ['/* testFn */'], + 'constant declaration: for' => ['/* testFor */'], + 'constant declaration: foreach' => ['/* testForeach */'], + 'constant declaration: function' => ['/* testFunction */'], + 'constant declaration: global' => ['/* testGlobal */'], + 'constant declaration: goto' => ['/* testGoto */'], + 'constant declaration: if' => ['/* testIf */'], + 'constant declaration: implements' => ['/* testImplements */'], + 'constant declaration: include' => ['/* testInclude */'], + 'constant declaration: include_once' => ['/* testIncludeOnce */'], + 'constant declaration: instanceof' => ['/* testInstanceOf */'], + 'constant declaration: insteadof' => ['/* testInsteadOf */'], + 'constant declaration: interface' => ['/* testInterface */'], + 'constant declaration: isset' => ['/* testIsset */'], + 'constant declaration: list' => ['/* testList */'], + 'constant declaration: match' => ['/* testMatch */'], + 'constant declaration: namespace' => ['/* testNamespace */'], + 'constant declaration: new' => ['/* testNew */'], + 'constant declaration: print' => ['/* testPrint */'], + 'constant declaration: private' => ['/* testPrivate */'], + 'constant declaration: protected' => ['/* testProtected */'], + 'constant declaration: public' => ['/* testPublic */'], + 'constant declaration: readonly' => ['/* testReadonly */'], + 'constant declaration: require' => ['/* testRequire */'], + 'constant declaration: require_once' => ['/* testRequireOnce */'], + 'constant declaration: return' => ['/* testReturn */'], + 'constant declaration: static' => ['/* testStatic */'], + 'constant declaration: switch' => ['/* testSwitch */'], + 'constant declaration: throws' => ['/* testThrows */'], + 'constant declaration: trait' => ['/* testTrait */'], + 'constant declaration: try' => ['/* testTry */'], + 'constant declaration: unset' => ['/* testUnset */'], + 'constant declaration: use' => ['/* testUse */'], + 'constant declaration: var' => ['/* testVar */'], + 'constant declaration: while' => ['/* testWhile */'], + 'constant declaration: yield' => ['/* testYield */'], + 'constant declaration: yield_from' => ['/* testYieldFrom */'], + 'constant declaration: and' => ['/* testAnd */'], + 'constant declaration: or' => ['/* testOr */'], + 'constant declaration: xor' => ['/* testXor */'], + + 'constant declaration: array in type' => ['/* testArrayIsTstringInConstType */'], + 'constant declaration: array, name after type' => ['/* testArrayNameForTypedConstant */'], + 'constant declaration: static, name after type' => ['/* testStaticIsNameForTypedConstant */'], + 'constant declaration: private, name after type' => ['/* testPrivateNameForUnionTypedConstant */'], + 'constant declaration: final, name after type' => ['/* testFinalNameForIntersectionTypedConstant */'], + + 'namespace declaration: class' => ['/* testKeywordAfterNamespaceShouldBeString */'], + 'namespace declaration (partial): my' => ['/* testNamespaceNameIsString1 */'], + 'namespace declaration (partial): class' => ['/* testNamespaceNameIsString2 */'], + 'namespace declaration (partial): foreach' => ['/* testNamespaceNameIsString3 */'], + + 'function declaration: eval' => ['/* testKeywordAfterFunctionShouldBeString */'], + 'function declaration with return by ref: switch' => ['/* testKeywordAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: static' => ['/* testKeywordStaticAfterFunctionByRefShouldBeString */'], + + 'function call: static' => ['/* testKeywordAsFunctionCallNameShouldBeStringStatic */'], + 'method call: static' => ['/* testKeywordAsMethodCallNameShouldBeStringStatic */'], + 'method call: static with dnf look a like param' => ['/* testKeywordAsFunctionCallNameShouldBeStringStaticDNFLookaLike */'], + ]; + + }//end dataStrings() + + + /** + * Test that context sensitive keyword is tokenized as keyword when it should be keyword. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedTokenType The expected token type. + * + * @dataProvider dataKeywords + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testKeywords($testMarker, $expectedTokenType) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_ANON_CLASS, T_MATCH_DEFAULT, T_STRING])); + $tokenArray = $tokens[$target]; + + $this->assertSame( + constant($expectedTokenType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' + ); + $this->assertSame( + $expectedTokenType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' + ); + + }//end testKeywords() + + + /** + * Data provider. + * + * @see testKeywords() + * + * @return array> + */ + public static function dataKeywords() + { + return [ + 'namespace: declaration' => [ + 'testMarker' => '/* testNamespaceIsKeyword */', + 'expectedTokenType' => 'T_NAMESPACE', + ], + 'array: default value in const decl' => [ + 'testMarker' => '/* testArrayIsKeywordInConstDefault */', + 'expectedTokenType' => 'T_ARRAY', + ], + 'static: type in constant declaration' => [ + 'testMarker' => '/* testStaticIsKeywordAsConstType */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: value in constant declaration' => [ + 'testMarker' => '/* testStaticIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_STATIC', + ], + + 'abstract: class declaration' => [ + 'testMarker' => '/* testAbstractIsKeyword */', + 'expectedTokenType' => 'T_ABSTRACT', + ], + 'class: declaration' => [ + 'testMarker' => '/* testClassIsKeyword */', + 'expectedTokenType' => 'T_CLASS', + ], + 'extends: in class declaration' => [ + 'testMarker' => '/* testExtendsIsKeyword */', + 'expectedTokenType' => 'T_EXTENDS', + ], + 'implements: in class declaration' => [ + 'testMarker' => '/* testImplementsIsKeyword */', + 'expectedTokenType' => 'T_IMPLEMENTS', + ], + 'use: in trait import' => [ + 'testMarker' => '/* testUseIsKeyword */', + 'expectedTokenType' => 'T_USE', + ], + 'insteadof: in trait import' => [ + 'testMarker' => '/* testInsteadOfIsKeyword */', + 'expectedTokenType' => 'T_INSTEADOF', + ], + 'as: in trait import' => [ + 'testMarker' => '/* testAsIsKeyword */', + 'expectedTokenType' => 'T_AS', + ], + 'const: declaration' => [ + 'testMarker' => '/* testConstIsKeyword */', + 'expectedTokenType' => 'T_CONST', + ], + 'private: property declaration' => [ + 'testMarker' => '/* testPrivateIsKeyword */', + 'expectedTokenType' => 'T_PRIVATE', + ], + 'protected: property declaration' => [ + 'testMarker' => '/* testProtectedIsKeyword */', + 'expectedTokenType' => 'T_PROTECTED', + ], + 'public: property declaration' => [ + 'testMarker' => '/* testPublicIsKeyword */', + 'expectedTokenType' => 'T_PUBLIC', + ], + 'var: property declaration' => [ + 'testMarker' => '/* testVarIsKeyword */', + 'expectedTokenType' => 'T_VAR', + ], + 'static: property declaration' => [ + 'testMarker' => '/* testStaticIsKeyword */', + 'expectedTokenType' => 'T_STATIC', + ], + 'readonly: property declaration' => [ + 'testMarker' => '/* testReadonlyIsKeywordForProperty */', + 'expectedTokenType' => 'T_READONLY', + ], + 'final: function declaration' => [ + 'testMarker' => '/* testFinalIsKeyword */', + 'expectedTokenType' => 'T_FINAL', + ], + 'function: declaration' => [ + 'testMarker' => '/* testFunctionIsKeyword */', + 'expectedTokenType' => 'T_FUNCTION', + ], + 'callable: param type declaration' => [ + 'testMarker' => '/* testCallableIsKeyword */', + 'expectedTokenType' => 'T_CALLABLE', + ], + 'readonly: anon class declaration' => [ + 'testMarker' => '/* testReadonlyIsKeywordForAnonClass */', + 'expectedTokenType' => 'T_READONLY', + ], + 'return: statement' => [ + 'testMarker' => '/* testReturnIsKeyword */', + 'expectedTokenType' => 'T_RETURN', + ], + + 'interface: declaration' => [ + 'testMarker' => '/* testInterfaceIsKeyword */', + 'expectedTokenType' => 'T_INTERFACE', + ], + 'trait: declaration' => [ + 'testMarker' => '/* testTraitIsKeyword */', + 'expectedTokenType' => 'T_TRAIT', + ], + 'enum: declaration' => [ + 'testMarker' => '/* testEnumIsKeyword */', + 'expectedTokenType' => 'T_ENUM', + ], + + 'new: named instantiation' => [ + 'testMarker' => '/* testNewIsKeyword */', + 'expectedTokenType' => 'T_NEW', + ], + 'instanceof: comparison' => [ + 'testMarker' => '/* testInstanceOfIsKeyword */', + 'expectedTokenType' => 'T_INSTANCEOF', + ], + 'clone' => [ + 'testMarker' => '/* testCloneIsKeyword */', + 'expectedTokenType' => 'T_CLONE', + ], + + 'if' => [ + 'testMarker' => '/* testIfIsKeyword */', + 'expectedTokenType' => 'T_IF', + ], + 'empty' => [ + 'testMarker' => '/* testEmptyIsKeyword */', + 'expectedTokenType' => 'T_EMPTY', + ], + 'elseif' => [ + 'testMarker' => '/* testElseIfIsKeyword */', + 'expectedTokenType' => 'T_ELSEIF', + ], + 'else' => [ + 'testMarker' => '/* testElseIsKeyword */', + 'expectedTokenType' => 'T_ELSE', + ], + 'endif' => [ + 'testMarker' => '/* testEndIfIsKeyword */', + 'expectedTokenType' => 'T_ENDIF', + ], + + 'for' => [ + 'testMarker' => '/* testForIsKeyword */', + 'expectedTokenType' => 'T_FOR', + ], + 'endfor' => [ + 'testMarker' => '/* testEndForIsKeyword */', + 'expectedTokenType' => 'T_ENDFOR', + ], + + 'foreach' => [ + 'testMarker' => '/* testForeachIsKeyword */', + 'expectedTokenType' => 'T_FOREACH', + ], + 'endforeach' => [ + 'testMarker' => '/* testEndForeachIsKeyword */', + 'expectedTokenType' => 'T_ENDFOREACH', + ], + + 'switch' => [ + 'testMarker' => '/* testSwitchIsKeyword */', + 'expectedTokenType' => 'T_SWITCH', + ], + 'case: in switch' => [ + 'testMarker' => '/* testCaseIsKeyword */', + 'expectedTokenType' => 'T_CASE', + ], + 'default: in switch' => [ + 'testMarker' => '/* testDefaultIsKeyword */', + 'expectedTokenType' => 'T_DEFAULT', + ], + 'endswitch' => [ + 'testMarker' => '/* testEndSwitchIsKeyword */', + 'expectedTokenType' => 'T_ENDSWITCH', + ], + 'break: in switch' => [ + 'testMarker' => '/* testBreakIsKeyword */', + 'expectedTokenType' => 'T_BREAK', + ], + 'continue: in switch' => [ + 'testMarker' => '/* testContinueIsKeyword */', + 'expectedTokenType' => 'T_CONTINUE', + ], + + 'do' => [ + 'testMarker' => '/* testDoIsKeyword */', + 'expectedTokenType' => 'T_DO', + ], + 'while' => [ + 'testMarker' => '/* testWhileIsKeyword */', + 'expectedTokenType' => 'T_WHILE', + ], + 'endwhile' => [ + 'testMarker' => '/* testEndWhileIsKeyword */', + 'expectedTokenType' => 'T_ENDWHILE', + ], + + 'try' => [ + 'testMarker' => '/* testTryIsKeyword */', + 'expectedTokenType' => 'T_TRY', + ], + 'throw: statement' => [ + 'testMarker' => '/* testThrowIsKeyword */', + 'expectedTokenType' => 'T_THROW', + ], + 'catch' => [ + 'testMarker' => '/* testCatchIsKeyword */', + 'expectedTokenType' => 'T_CATCH', + ], + 'finally' => [ + 'testMarker' => '/* testFinallyIsKeyword */', + 'expectedTokenType' => 'T_FINALLY', + ], + + 'global' => [ + 'testMarker' => '/* testGlobalIsKeyword */', + 'expectedTokenType' => 'T_GLOBAL', + ], + 'echo' => [ + 'testMarker' => '/* testEchoIsKeyword */', + 'expectedTokenType' => 'T_ECHO', + ], + 'print: statement' => [ + 'testMarker' => '/* testPrintIsKeyword */', + 'expectedTokenType' => 'T_PRINT', + ], + 'die: statement' => [ + 'testMarker' => '/* testDieIsKeyword */', + 'expectedTokenType' => 'T_EXIT', + ], + 'eval' => [ + 'testMarker' => '/* testEvalIsKeyword */', + 'expectedTokenType' => 'T_EVAL', + ], + 'exit: statement' => [ + 'testMarker' => '/* testExitIsKeyword */', + 'expectedTokenType' => 'T_EXIT', + ], + 'isset' => [ + 'testMarker' => '/* testIssetIsKeyword */', + 'expectedTokenType' => 'T_ISSET', + ], + 'unset' => [ + 'testMarker' => '/* testUnsetIsKeyword */', + 'expectedTokenType' => 'T_UNSET', + ], + + 'include' => [ + 'testMarker' => '/* testIncludeIsKeyword */', + 'expectedTokenType' => 'T_INCLUDE', + ], + 'include_once' => [ + 'testMarker' => '/* testIncludeOnceIsKeyword */', + 'expectedTokenType' => 'T_INCLUDE_ONCE', + ], + 'require' => [ + 'testMarker' => '/* testRequireIsKeyword */', + 'expectedTokenType' => 'T_REQUIRE', + ], + 'require_once' => [ + 'testMarker' => '/* testRequireOnceIsKeyword */', + 'expectedTokenType' => 'T_REQUIRE_ONCE', + ], + + 'list' => [ + 'testMarker' => '/* testListIsKeyword */', + 'expectedTokenType' => 'T_LIST', + ], + 'goto' => [ + 'testMarker' => '/* testGotoIsKeyword */', + 'expectedTokenType' => 'T_GOTO', + ], + 'match' => [ + 'testMarker' => '/* testMatchIsKeyword */', + 'expectedTokenType' => 'T_MATCH', + ], + 'default: in match expression' => [ + 'testMarker' => '/* testMatchDefaultIsKeyword */', + 'expectedTokenType' => 'T_MATCH_DEFAULT', + ], + 'fn' => [ + 'testMarker' => '/* testFnIsKeyword */', + 'expectedTokenType' => 'T_FN', + ], + + 'yield' => [ + 'testMarker' => '/* testYieldIsKeyword */', + 'expectedTokenType' => 'T_YIELD', + ], + 'yield from' => [ + 'testMarker' => '/* testYieldFromIsKeyword */', + 'expectedTokenType' => 'T_YIELD_FROM', + ], + + 'declare' => [ + 'testMarker' => '/* testDeclareIsKeyword */', + 'expectedTokenType' => 'T_DECLARE', + ], + 'enddeclare' => [ + 'testMarker' => '/* testEndDeclareIsKeyword */', + 'expectedTokenType' => 'T_ENDDECLARE', + ], + + 'and: in if' => [ + 'testMarker' => '/* testAndIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_AND', + ], + 'or: in if' => [ + 'testMarker' => '/* testOrIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_OR', + ], + 'xor: in if' => [ + 'testMarker' => '/* testXorIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_XOR', + ], + + 'class: anon class declaration' => [ + 'testMarker' => '/* testAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_ANON_CLASS', + ], + 'extends: anon class declaration' => [ + 'testMarker' => '/* testExtendsInAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_EXTENDS', + ], + 'implements: anon class declaration' => [ + 'testMarker' => '/* testImplementsInAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_IMPLEMENTS', + ], + 'static: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationStaticIsKeyword */', + 'expectedTokenType' => 'T_STATIC', + ], + 'namespace: operator' => [ + 'testMarker' => '/* testNamespaceInNameIsKeyword */', + 'expectedTokenType' => 'T_NAMESPACE', + ], + + 'static: closure declaration' => [ + 'testMarker' => '/* testStaticIsKeywordBeforeClosure */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: parameter type (illegal)' => [ + 'testMarker' => '/* testStaticIsKeywordWhenParamType */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: arrow function declaration' => [ + 'testMarker' => '/* testStaticIsKeywordBeforeArrow */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: return type for arrow function' => [ + 'testMarker' => '/* testStaticIsKeywordWhenReturnType */', + 'expectedTokenType' => 'T_STATIC', + ], + 'static: property modifier before DNF' => [ + 'testMarker' => '/* testStaticIsKeywordPropertyModifierBeforeDNF */', + 'expectedTokenType' => 'T_STATIC', + ], + ]; + + }//end dataKeywords() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc new file mode 100644 index 000000000..a6cf511c2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc @@ -0,0 +1,17 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DNFTypesParseError1Test extends AbstractTokenizerTestCase +{ + + + /** + * Document handling for a DNF type / parse error where the last significant type specific token is an open parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeCantEndOnOpenParenthesis + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeCantEndOnOpenParenthesis($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + $token = $tokens[$openPtr]; + + // Verify that the open parenthesis is tokenized as a normal parenthesis. + $this->assertSame(T_OPEN_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (type)'); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + }//end testBrokenDNFTypeCantEndOnOpenParenthesis() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeCantEndOnOpenParenthesis() + * + * @return array> + */ + public static function dataBrokenDNFTypeCantEndOnOpenParenthesis() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeEndOnOpenParenthesis */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeEndOnOpenParenthesis */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeEndOnOpenParenthesis */'], + 'Return type' => ['/* testBrokenReturnDNFTypeEndOnOpenParenthesis */'], + ]; + + }//end dataBrokenDNFTypeCantEndOnOpenParenthesis() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc new file mode 100644 index 000000000..792975828 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc @@ -0,0 +1,48 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class DNFTypesParseError2Test extends AbstractTokenizerTestCase +{ + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + // Verify that the unmatched open parenthesis is tokenized as a normal parenthesis. + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + $token = $tokens[$openPtr]; + + $this->assertSame(T_OPEN_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (type)'); + + // Verify that the type intersection is still tokenized as T_BITWISE_AND as the type declaration + // is not recognized as a valid type declaration. + $intersectPtr = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION], '&'); + $token = $tokens[$intersectPtr]; + + $this->assertSame(T_BITWISE_AND, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (type)'); + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeParensMissingClose */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeParensMissingClose */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeParensMissingClose */'], + 'Return type' => ['/* testBrokenReturnDNFTypeParensMissingClose */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + // Verify that the unmatched open parenthesis is tokenized as a normal parenthesis. + $closePtr = $this->getTargetToken($testMarker, [T_CLOSE_PARENTHESIS, T_TYPE_CLOSE_PARENTHESIS], ')'); + $token = $tokens[$closePtr]; + + $this->assertSame(T_CLOSE_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_CLOSE_PARENTHESIS (type)'); + + // Verify that the type intersection is still tokenized as T_BITWISE_AND as the type declaration + // is not recognized as a valid type declaration. + $intersectPtr = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION], '&'); + $token = $tokens[$intersectPtr]; + + $this->assertSame(T_BITWISE_AND, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (type)'); + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeParensMissingOpen */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeParensMissingOpen */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeParensMissingOpen */'], + 'Return type' => ['/* testBrokenReturnDNFTypeParensMissingOpen */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis, + * but also contains a set of matched parentheses. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $startPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + + for ($i = $startPtr; $i < $this->phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + if ($tokens[$i]['code'] === T_EQUAL + || $tokens[$i]['code'] === T_VARIABLE + || $tokens[$i]['code'] === T_OPEN_CURLY_BRACKET + ) { + // Reached the end of the type. + break; + } + + $errorPrefix = 'Token tokenized as '.$tokens[$i]['type']; + + // Verify that type tokens have not been retokenized to `T_TYPE_*` tokens for broken type declarations. + switch ($tokens[$i]['content']) { + case '|': + $this->assertSame(T_BITWISE_OR, $tokens[$i]['code'], $errorPrefix.', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokens[$i]['type'], $errorPrefix.', not T_BITWISE_OR (type)'); + break; + + case '&': + $this->assertSame(T_BITWISE_AND, $tokens[$i]['code'], $errorPrefix.', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokens[$i]['type'], $errorPrefix.', not T_BITWISE_AND (type)'); + break; + + case '(': + // Verify that the open parenthesis is tokenized as a normal parenthesis. + $this->assertSame(T_OPEN_PARENTHESIS, $tokens[$i]['code'], $errorPrefix.', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $tokens[$i]['type'], $errorPrefix.', not T_OPEN_PARENTHESIS (type)'); + break; + + case ')': + $this->assertSame(T_CLOSE_PARENTHESIS, $tokens[$i]['code'], $errorPrefix.', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $tokens[$i]['type'], $errorPrefix.', not T_CLOSE_PARENTHESIS (type)'); + break; + + default: + break; + }//end switch + }//end for + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + { + return [ + 'OO const type - missing one close parenthesis' => ['/* testBrokenConstDNFTypeParensMissingOneClose */'], + 'OO property type - missing one open parenthesis' => ['/* testBrokenPropertyDNFTypeParensMissingOneOpen */'], + 'Parameter type - missing one close parenthesis' => ['/* testBrokenParamDNFTypeParensMissingOneClose */'], + 'Return type - missing one open parenthesis' => ['/* testBrokenReturnDNFTypeParensMissingOneOpen */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc new file mode 100644 index 000000000..c1a38c79e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc @@ -0,0 +1,270 @@ + 10 ) {} + +/* testParensOwnerFor */ +for ($i =0; $i < /* testParensNoOwnerInForCondition */ ( CONST_A & CONST_B ); $i++ ); + +/* testParensOwnerMatch */ +$match = match(CONST_A & CONST_B) { + default => $a, +}; + +/* testParensOwnerArray */ +$array = array ( + 'text', + \CONST_A & \Fully\Qualified\CONST_B, + /* testParensNoOwnerFunctionCallWithAmpersandInCallable */ + do_something($a, /* testParensOwnerArrowFn */ fn($b) => $a & $b, $c), +); + +/* testParensOwnerListWithRefVars */ +list(&$a, &$b) = $array; + +/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamPlain */ +callMe(label: false); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamUnion */ +callMe(label: CONST_A | CONST_B); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */ +callMe(label: CONST_A & CONST_B); + +\Z1\call11( + /* testParensNoOwnerFunctionCallInNamedParam */ + param1: \Z2\call12(), + /* testParensOwnerArrowFunctionInNamedParam */ + param2: fn (): /* testDNFTypeArrowFnReturnInNamedParam */ int|(\Countable&\Iterable) + /* testParensNoOwnerFunctionCallInArrowFnReturn */ + => \Z3\call13(), + /* testParensOwnerClosureInNamedParam */ + param3: function (): /* testDNFTypeClosureReturnInNamedParam */ int|(\DateTime&\ArrayObject) { + /* testParensNoOwnerFunctionCallInClosureReturn */ + return \Z4\call14(); + }, +); + +/* testSwitchControlStructureCondition */ +switch (CONST_A | CONST_B) { + /* testFunctionCallInSwitchCaseCondition */ + case get_bool(): + /* testFunctionCallInSwitchCaseBody */ + \Name\functionInSwitch(); + break; + + default: + /* testFunctionCallInSwitchDefaultBody */ + functionInSwitch(); + break; +} + +/* testIfAlternativeSyntaxCondition */ +if (true): + /* testFunctionCallInIfBody */ + \B\call(); +/* testElseIfAlternativeSyntaxCondition */ +elseif (10): + /* testFunctionCallInElseIfBody */ + C\call(); +else: + /* testFunctionCallInElseBody */ + \C\call3(); +endif; + +gotolabel: + /* testFunctionCallInGotoBody */ + \doSomething(); + +/* testWhileAlternativeSyntaxCondition */ +while ($c3): + /* testFunctionCallInWhileBody */ + \D\call4(); +endwhile; + +/* testForAlternativeSyntaxCondition */ +for ($i = 0; $i < 10; $i++): + /* testFunctionCallInForBody */ + \F\call5(); +endfor; + +/* testForEachAlternativeSyntaxCondition */ +foreach ($array as $key => $value): + /* testFunctionCallInForeachBody */ + \G\call6(); +endforeach; + +/* + * DNF parentheses. + */ + +abstract class DNFTypes { + /* testDNFTypeOOConstUnqualifiedClasses */ + public const (A&B)|D UNQUALIFIED = new Foo; + + /* testDNFTypeOOConstReverseModifierOrder */ + protected final const int|(Foo&Bar)|float MODIFIERS_REVERSED /* testParensNoOwnerOOConstDefaultValue */ = (E_WARNING & E_NOTICE) | E_DEPRECATED; + + const + /* testDNFTypeOOConstMulti1 */ + (A&B) | + /* testDNFTypeOOConstMulti2 */ + (C&D) | // phpcs:ignore Stnd.Cat.Sniff + /* testDNFTypeOOConstMulti3 */ + (Y&D) + | null MULTI_DNF = null; + + /* testDNFTypeOOConstNamespaceRelative */ + final protected const (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testDNFTypeOOConstPartiallyQualified */ + const Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testDNFTypeOOConstFullyQualified */ + const (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameC FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + + /* testDNFTypePropertyUnqualifiedClasses */ + public static (Foo&Bar)|array $obj; + + /* testDNFTypePropertyReverseModifierOrder */ + static protected string|(A&B)|int $dnf /* testParensNoOwnerPropertyDefaultValue1 */ = ( E_WARNING & E_NOTICE ) | /* testParensNoOwnerPropertyDefaultValue2 */ (E_ALL & E_DEPRECATED); + + private + /* testDNFTypePropertyMultiNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB) | + /* testDNFTypePropertyMultiPartiallyQualified */ + (Partially\Qualified\NameA&Partially\Qualified\NameB) | // phpcs:ignore Stnd.Cat.Sniff + false + /* testDNFTypePropertyMultiFullyQualified */ + | (\Fully\Qualified\NameA&\Fully\Qualified\NameB) $multiDnf; + + /* testDNFTypePropertyWithReadOnlyKeyword1 */ + protected readonly (A&B) | /* testDNFTypePropertyWithReadOnlyKeyword2 */ (C&D) $readonly; + + /* testDNFTypePropertyWithStaticAndReadOnlyKeywords */ + static readonly (A&B&C)|array $staticReadonly; + + /* testDNFTypePropertyWithOnlyStaticKeyword */ + static (A&B&C)|true $onlyStaticModified; + + /* testDNFTypeWithPHP84FinalKeyword */ + final (className&InterfaceName)|false $finalKeywordA; + + /* testDNFTypeWithPHP84FinalKeywordAndStatic */ + final static (\className&\InterfaceName)|false $finalKeywordB; + + public function paramTypes( + /* testDNFTypeParam1WithAttribute */ + #[MyAttribute] + (\Foo&Bar)|int|float $paramA /* testParensNoOwnerParamDefaultValue */ = SOMETHING | (CONSTANT_A & CONSTANT_B), + + /* testDNFTypeParam2 */ + (Foo&\Bar) /* testDNFTypeParam3 */ |(Baz&Fop) &...$paramB, + ) { + /* testParensNoOwnerInReturnValue1 */ + return ( + /* testParensNoOwnerInReturnValue2 */ + ($a1 & $b1) | + /* testParensNoOwnerInReturnValue3 */ + ($a2 & $b2) + ) + $c; + } + + public function identifierNames( + /* testDNFTypeParamNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB)|false $paramA, + /* testDNFTypeParamPartiallyQualified */ + Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) $paramB, + /* testDNFTypeParamFullyQualified */ + name|(\Fully\Qualified\NameA&\Fully\Qualified\NameB) $paramC, + ) {} + + public function __construct( + /* testDNFTypeConstructorPropertyPromotion1 */ + public (A&B)| /* testDNFTypeConstructorPropertyPromotion2 */ (A&D) $property + ) {} + + public function returnType()/* testDNFTypeReturnType1 */ : A|(B&D)|/* testDNFTypeReturnType2 */(B&W)|null {} + + abstract public function abstractMethod(): /* testDNFTypeAbstractMethodReturnType1 */ (X&Y) /* testDNFTypeAbstractMethodReturnType2 */ |(W&Z); + + public function identifierNamesReturnRelative( + ) : /* testDNFTypeReturnTypeNamespaceRelative */ (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC {} + + public function identifierNamesReturnPQ( + ) : /* testDNFTypeReturnPartiallyQualified */Partially\Qualified\NameA|(Partially\Qualified\NameB&Partially\Qualified\NameC) {} + + // Illegal type: segments which are strict subsets of others are disallowed, but that's not the concern of the tokenizer. + public function identifierNamesReturnFQ( + ) /* testDNFTypeReturnFullyQualified */ : (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameB {} +} + +function globalFunctionWithSpreadAndReference( + /* testDNFTypeWithReference */ + float|(B&A) &$paramA, + /* testDNFTypeWithSpreadOperator */ + string|(B&D) ...$paramB +) {} + + +$closureWithParamType = function ( /* testDNFTypeClosureParamIllegalNullable */ ?(A&B)|bool $string) {}; + +/* testParensOwnerClosureAmpersandInDefaultValue */ +$closureWithReturnType = function ($string = NONSENSE & FAKE) /* testDNFTypeClosureReturn */ : (\Package\MyA&PackageB)|null {}; + +$closureWithUseAndReturnType = function ($foo) use ($a) /* testDNFTypeClosureWithUseReturn */ : null|(Foo&\Bar)|false {}; + +/* testParensOwnerArrowDNFUsedWithin */ +$arrowWithParamType = fn ( + /* testDNFTypeArrowParam */ + int|(A&B&C)|array $param, + /* testParensNoOwnerAmpersandInDefaultValue */ ?int $int = (CONSTA & CONSTB )| CONST_C +) + /* testParensNoOwnerInArrowReturnExpression */ + => ($param & $foo ) | $int; + +$arrowWithReturnType = fn ($param) : /* testDNFTypeArrowReturnType */ int|(A&B) => $param * 10; + +$arrowWithParamReturnByRef = fn &( + /* testDNFTypeArrowParamWithReturnByRef */ + (A&B)|null $param +) => $param * 10; + +function InvalidSyntaxes( + /* testDNFTypeParamIllegalUnnecessaryParens */ + (A&B) $parensNotNeeded, + + /* testDNFTypeParamIllegalIntersectUnionReversed */ + A&(B|D) $onlyIntersectAllowedWithinParensAndUnionOutside, + + /* testDNFTypeParamIllegalNestedParens */ + A|(B&(D|W)|null) $nestedParensNotAllowed, +) {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php new file mode 100644 index 000000000..3c9fcb80b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php @@ -0,0 +1,539 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class DNFTypesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that parentheses when **not** used in a type declaration are correctly tokenized. + * + * @param string $testMarker The comment prefacing the target token. + * @param bool $skipCheckInside Optional. Skip checking correct token type inside the parentheses. + * Use judiciously for combined normal + DNF tests only. + * + * @dataProvider dataNormalParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNormalParentheses($testMarker, $skipCheckInside=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + $this->assertSame('(', $opener['content'], 'Content of type open parenthesis is not "("'); + $this->assertSame(T_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $opener['type'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (type)'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + $this->assertSame(')', $closer['content'], 'Content of type close parenthesis is not ")"'); + $this->assertSame(T_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $closer['type'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (type)'); + + if ($skipCheckInside === false) { + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + // If there are ampersands, make sure these are tokenized as bitwise and. + if ($tokens[$i]['content'] === '&') { + $this->assertSame(T_BITWISE_AND, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_AND (type)'); + } + + // If there are pipes, make sure these are tokenized as bitwise or. + if ($tokens[$i]['content'] === '|') { + $this->assertSame(T_BITWISE_OR, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_OR (type)'); + } + } + } + + $before = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($openPtr - 1), null, true); + if ($before !== false && $tokens[$before]['content'] === '|') { + $this->assertSame( + T_BITWISE_OR, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_BITWISE_OR (code)' + ); + $this->assertSame( + 'T_BITWISE_OR', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_BITWISE_OR (type)' + ); + } + + $after = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closePtr + 1), null, true); + if ($after !== false && $tokens[$after]['content'] === '|') { + $this->assertSame( + T_BITWISE_OR, + $tokens[$after]['code'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_BITWISE_OR (code)' + ); + $this->assertSame( + 'T_BITWISE_OR', + $tokens[$after]['type'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_BITWISE_OR (type)' + ); + } + + }//end testNormalParentheses() + + + /** + * Data provider. + * + * @see testNormalParentheses() + * + * @return array> + */ + public static function dataNormalParentheses() + { + // "Owner" offsets are relative to the open parenthesis. + return [ + 'parens without owner' => [ + 'testMarker' => '/* testParensNoOwner */', + ], + 'parens without owner in ternary then' => [ + 'testMarker' => '/* testParensNoOwnerInTernary */', + ], + 'parens without owner in short ternary' => [ + 'testMarker' => '/* testParensNoOwnerInShortTernary */', + ], + 'parens without owner in ternary then (fn call in inline then)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryA */', + ], + 'parens without owner in ternary then (fn call in inline else)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryB */', + ], + 'parens without owner in short ternary (fn call)' => [ + 'testMarker' => '/* testPFnCallarensNoOwnerInShortTernary */', + ], + 'parens with owner: function; & in default value' => [ + 'testMarker' => '/* testParensOwnerFunctionAmpersandInDefaultValue */', + ], + 'parens with owner: closure; param declared by & ref' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandParamRef */', + ], + 'parens with owner: if' => [ + 'testMarker' => '/* testParensOwnerIf */', + ], + 'parens without owner in if condition' => [ + 'testMarker' => '/* testParensNoOwnerInIfCondition */', + ], + 'parens with owner: for' => [ + 'testMarker' => '/* testParensOwnerFor */', + ], + 'parens without owner in for condition' => [ + 'testMarker' => '/* testParensNoOwnerInForCondition */', + ], + 'parens with owner: match' => [ + 'testMarker' => '/* testParensOwnerMatch */', + ], + 'parens with owner: array' => [ + 'testMarker' => '/* testParensOwnerArray */', + ], + 'parens without owner in array; function call with & in callable' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithAmpersandInCallable */', + ], + 'parens with owner: fn; & in return value' => [ + 'testMarker' => '/* testParensOwnerArrowFn */', + ], + 'parens with owner: list with reference vars' => [ + 'testMarker' => '/* testParensOwnerListWithRefVars */', + ], + 'parens without owner, function call with DNF look-a-like param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */', + ], + 'parens without owner, function call, named param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamPlain */', + ], + 'parens without owner, function call, named param + bitwise or' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamUnion */', + ], + 'parens without owner, function call, named param + bitwise and' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */', + ], + 'parens without owner, function call in named param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInNamedParam */', + ], + 'parens with owner: fn; in named param' => [ + 'testMarker' => '/* testParensOwnerArrowFunctionInNamedParam */', + ], + 'parens without owner, function call in named param arrow return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInArrowFnReturn */', + ], + 'parens with owner: closure; in named param' => [ + 'testMarker' => '/* testParensOwnerClosureInNamedParam */', + ], + 'parens without owner, function call, named param closure return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInClosureReturn */', + ], + 'parens with owner: switch condition' => [ + 'testMarker' => '/* testSwitchControlStructureCondition */', + ], + 'parens without owner in switch-case condition' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseCondition */', + ], + 'parens without owner in switch-case body' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseBody */', + ], + 'parens without owner in switch-default body' => [ + 'testMarker' => '/* testFunctionCallInSwitchDefaultBody */', + ], + 'parens with owner: if condition, alternative syntax' => [ + 'testMarker' => '/* testIfAlternativeSyntaxCondition */', + ], + 'parens without owner in if body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInIfBody */', + ], + 'parens with owner: elseif condition, alternative syntax' => [ + 'testMarker' => '/* testElseIfAlternativeSyntaxCondition */', + ], + 'parens without owner in elseif body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseIfBody */', + ], + 'parens without owner in else body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseBody */', + ], + 'parens without owner in goto body' => [ + 'testMarker' => '/* testFunctionCallInGotoBody */', + ], + 'parens with owner: while condition, alternative syntax' => [ + 'testMarker' => '/* testWhileAlternativeSyntaxCondition */', + ], + 'parens without owner in while body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInWhileBody */', + ], + 'parens with owner: for condition, alternative syntax' => [ + 'testMarker' => '/* testForAlternativeSyntaxCondition */', + ], + 'parens without owner in for body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForBody */', + ], + 'parens with owner: foreach condition, alternative syntax' => [ + 'testMarker' => '/* testForEachAlternativeSyntaxCondition */', + ], + 'parens without owner in foreach body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForeachBody */', + ], + + 'parens without owner in OO const default value' => [ + 'testMarker' => '/* testParensNoOwnerOOConstDefaultValue */', + ], + 'parens without owner in property default 1' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue1 */', + ], + 'parens without owner in property default 2' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue2 */', + ], + 'parens without owner in param default value' => [ + 'testMarker' => '/* testParensNoOwnerParamDefaultValue */', + ], + 'parens without owner in return statement 1' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue1 */', + ], + 'parens without owner in return statement 2' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue2 */', + ], + 'parens without owner in return statement 3' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue3 */', + ], + 'parens with owner: closure; & in default value' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandInDefaultValue */', + ], + 'parens with owner: fn; dnf used within' => [ + 'testMarker' => '/* testParensOwnerArrowDNFUsedWithin */', + 'skipCheckInside' => true, + ], + 'parens without owner: default value for param in arrow function' => [ + 'testMarker' => '/* testParensNoOwnerAmpersandInDefaultValue */', + ], + 'parens without owner in arrow function return expression' => [ + 'testMarker' => '/* testParensNoOwnerInArrowReturnExpression */', + ], + ]; + + }//end dataNormalParentheses() + + + /** + * Test that parentheses when used in a DNF type declaration are correctly tokenized. + * + * Includes verifying that: + * - the tokens between the parentheses all have a "nested_parenthesis" key. + * - all ampersands between the parentheses are tokenized as T_TYPE_INTERSECTION. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataDNFTypeParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFTypeParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + $this->assertSame('(', $opener['content'], 'Content of type open parenthesis is not "("'); + $this->assertSame(T_TYPE_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_TYPE_OPEN_PARENTHESIS', $opener['type'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (type)'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + $this->assertSame(')', $closer['content'], 'Content of type close parenthesis is not ")"'); + $this->assertSame(T_TYPE_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_TYPE_CLOSE_PARENTHESIS', $closer['type'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (type)'); + + $intersectionCount = 0; + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + if ($tokens[$i]['content'] === '&') { + $this->assertSame( + T_TYPE_INTERSECTION, + $tokens[$i]['code'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_INTERSECTION (code)' + ); + $this->assertSame( + 'T_TYPE_INTERSECTION', + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_INTERSECTION (type)' + ); + ++$intersectionCount; + } + + // Not valid, but that's irrelevant for the tokenization. + if ($tokens[$i]['content'] === '|') { + $this->assertSame(T_TYPE_UNION, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_UNION (code)'); + $this->assertSame('T_TYPE_UNION', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_UNION (type)'); + + // For the purposes of this test, presume it was intended as an intersection. + ++$intersectionCount; + } + }//end for + + $this->assertGreaterThanOrEqual(1, $intersectionCount, 'Did not find an intersection "&" between the DNF type parentheses'); + + $before = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($openPtr - 1), null, true); + if ($before !== false && $tokens[$before]['content'] === '|') { + $this->assertSame( + T_TYPE_UNION, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_TYPE_UNION (code)' + ); + $this->assertSame( + 'T_TYPE_UNION', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_TYPE_UNION (type)' + ); + } + + // Invalid, but that's not relevant for the tokenization. + if ($before !== false && $tokens[$before]['content'] === '?') { + $this->assertSame( + T_NULLABLE, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_NULLABLE (code)' + ); + $this->assertSame( + 'T_NULLABLE', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_NULLABLE (type)' + ); + } + + $after = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closePtr + 1), null, true); + if ($after !== false && $tokens[$after]['content'] === '|') { + $this->assertSame( + T_TYPE_UNION, + $tokens[$after]['code'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_TYPE_UNION (code)' + ); + $this->assertSame( + 'T_TYPE_UNION', + $tokens[$after]['type'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_TYPE_UNION (type)' + ); + } + + }//end testDNFTypeParentheses() + + + /** + * Data provider. + * + * @see testDNFTypeParentheses() + * + * @return array> + */ + public static function dataDNFTypeParentheses() + { + return [ + 'arrow function return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeArrowFnReturnInNamedParam */', + ], + 'closure return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeClosureReturnInNamedParam */', + ], + + 'OO const type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstUnqualifiedClasses */', + ], + 'OO const type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypeOOConstReverseModifierOrder */', + ], + 'OO const type: multi-dnf part 1' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti1 */', + ], + 'OO const type: multi-dnf part 2' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti2 */', + ], + 'OO const type: multi-dnf part 3' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti3 */', + ], + 'OO const type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeOOConstNamespaceRelative */', + ], + 'OO const type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstPartiallyQualified */', + ], + 'OO const type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstFullyQualified */', + ], + + 'OO property type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyUnqualifiedClasses */', + ], + 'OO property type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypePropertyReverseModifierOrder */', + ], + 'OO property type: multi-dnf namespace relative classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiNamespaceRelative */', + ], + 'OO property type: multi-dnf partially qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiPartiallyQualified */', + ], + 'OO property type: multi-dnf fully qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiFullyQualified */', + ], + 'OO property type: multi-dnf with readonly keyword 1' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword1 */', + ], + 'OO property type: multi-dnf with readonly keyword 2' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword2 */', + ], + 'OO property type: with static and readonly keywords' => [ + 'testMarker' => '/* testDNFTypePropertyWithStaticAndReadOnlyKeywords */', + ], + 'OO property type: with only static keyword' => [ + 'testMarker' => '/* testDNFTypePropertyWithOnlyStaticKeyword */', + ], + 'OO property type: with only final keyword' => [ + 'testMarker' => '/* testDNFTypeWithPHP84FinalKeyword */', + ], + 'OO property type: with final and static keyword' => [ + 'testMarker' => '/* testDNFTypeWithPHP84FinalKeywordAndStatic */', + ], + + 'OO method param type: first param' => [ + 'testMarker' => '/* testDNFTypeParam1WithAttribute */', + ], + 'OO method param type: second param, first DNF' => [ + 'testMarker' => '/* testDNFTypeParam2 */', + ], + 'OO method param type: second param, second DNF' => [ + 'testMarker' => '/* testDNFTypeParam3 */', + ], + 'OO method param type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeParamNamespaceRelative */', + ], + 'OO method param type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamPartiallyQualified */', + ], + 'OO method param type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamFullyQualified */', + ], + 'Constructor property promotion with multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion1 */', + ], + 'Constructor property promotion with multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion2 */', + ], + 'OO method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeReturnType1 */', + ], + 'OO method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeReturnType2 */', + ], + 'OO abstract method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType1 */', + ], + 'OO abstract method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType2 */', + ], + 'OO method return type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeReturnTypeNamespaceRelative */', + ], + 'OO method return type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnPartiallyQualified */', + ], + 'OO method return type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnFullyQualified */', + ], + 'function param type: with reference' => [ + 'testMarker' => '/* testDNFTypeWithReference */', + ], + 'function param type: with spread' => [ + 'testMarker' => '/* testDNFTypeWithSpreadOperator */', + ], + 'closure param type: with illegal nullable' => [ + 'testMarker' => '/* testDNFTypeClosureParamIllegalNullable */', + ], + 'closure return type' => [ + 'testMarker' => '/* testDNFTypeClosureReturn */', + ], + 'closure with use return type' => [ + 'testMarker' => '/* testDNFTypeClosureWithUseReturn */', + ], + + 'arrow function param type' => [ + 'testMarker' => '/* testDNFTypeArrowParam */', + ], + 'arrow function return type' => [ + 'testMarker' => '/* testDNFTypeArrowReturnType */', + ], + 'arrow function param type with return by ref' => [ + 'testMarker' => '/* testDNFTypeArrowParamWithReturnByRef */', + ], + + 'illegal syntax: unnecessary parentheses (no union)' => [ + 'testMarker' => '/* testDNFTypeParamIllegalUnnecessaryParens */', + ], + 'illegal syntax: union within parentheses, intersect outside' => [ + 'testMarker' => '/* testDNFTypeParamIllegalIntersectUnionReversed */', + ], + 'illegal syntax: nested parentheses' => [ + 'testMarker' => '/* testDNFTypeParamIllegalNestedParens */', + ], + ]; + + }//end dataDNFTypeParentheses() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php new file mode 100644 index 000000000..c398aa6cb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php @@ -0,0 +1,255 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DefaultKeywordTest extends AbstractTokenizerTestCase +{ + + + /** + * Test the retokenization of the `default` keyword for match structure to `T_MATCH_DEFAULT`. + * + * Note: Cases and default structures within a match structure do *NOT* get case/default scope + * conditions, in contrast to case and default structures in switch control structures. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataMatchDefault + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testMatchDefault($testMarker, $testContent='default') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_MATCH_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (code)'); + $this->assertSame('T_MATCH_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (type)'); + + }//end testMatchDefault() + + + /** + * Data provider. + * + * @see testMatchDefault() + * + * @return array> + */ + public static function dataMatchDefault() + { + return [ + 'simple_match_default' => [ + 'testMarker' => '/* testSimpleMatchDefault */', + ], + 'match_default_in_switch_case_1' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase1 */', + ], + 'match_default_in_switch_case_2' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase2 */', + ], + 'match_default_in_switch_default' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchDefault */', + ], + 'match_default_containing_switch' => [ + 'testMarker' => '/* testMatchDefault */', + ], + + 'match_default_with_nested_long_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_long_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_long_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInLongArray */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_short_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInShortArray */', + 'testContent' => 'DEFAULT', + ], + ]; + + }//end dataMatchDefault() + + + /** + * Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively + * impact the tokenization of `T_DEFAULT` tokens in switch control structures. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataSwitchDefault + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testSwitchDefault($testMarker, $testContent='default') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (code)'); + $this->assertSame('T_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (type)'); + + }//end testSwitchDefault() + + + /** + * Data provider. + * + * @see testSwitchDefault() + * + * @return array> + */ + public static function dataSwitchDefault() + { + return [ + 'simple_switch_default' => [ + 'testMarker' => '/* testSimpleSwitchDefault */', + ], + 'simple_switch_default_with_curlies' => [ + 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', + ], + 'switch_default_toplevel' => [ + 'testMarker' => '/* testSwitchDefault */', + ], + 'switch_default_nested_in_match_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + ], + 'switch_default_nested_in_match_default' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + ], + ]; + + }//end dataSwitchDefault() + + + /** + * Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively + * impact the tokenization of `T_STRING` tokens with the contents 'default' which aren't in + * actual fact the default keyword. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotDefaultKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotDefaultKeyword() + + + /** + * Data provider. + * + * @see testNotDefaultKeyword() + * + * @return array> + */ + public static function dataNotDefaultKeyword() + { + return [ + 'class-constant-as-short-array-key' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKey */', + ], + 'class-property-as-short-array-key' => [ + 'testMarker' => '/* testClassPropertyAsShortArrayKey */', + ], + 'namespaced-constant-as-short-array-key' => [ + 'testMarker' => '/* testNamespacedConstantAsShortArrayKey */', + ], + 'fqn-global-constant-as-short-array-key' => [ + 'testMarker' => '/* testFQNGlobalConstantAsShortArrayKey */', + ], + 'class-constant-as-long-array-key' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKey */', + ], + 'class-constant-as-yield-key' => [ + 'testMarker' => '/* testClassConstantAsYieldKey */', + ], + + 'class-constant-as-long-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatch */', + ], + 'class-constant-as-long-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-short-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatch */', + ], + 'class-constant-as-short-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-long-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyWithNestedMatch */', + ], + 'class-constant-as-short-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyWithNestedMatch */', + ], + + 'class-constant-in-switch-case' => [ + 'testMarker' => '/* testClassConstantInSwitchCase */', + ], + 'class-property-in-switch-case' => [ + 'testMarker' => '/* testClassPropertyInSwitchCase */', + ], + 'namespaced-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespacedConstantInSwitchCase */', + ], + 'namespace-relative-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespaceRelativeConstantInSwitchCase */', + ], + + 'class-constant-declaration' => [ + 'testMarker' => '/* testClassConstant */', + ], + 'class-method-declaration' => [ + 'testMarker' => '/* testMethodDeclaration */', + 'testContent' => 'default', + ], + ]; + + }//end dataNotDefaultKeyword() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php similarity index 94% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php index ad1a411ff..5258d9c16 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php @@ -6,14 +6,14 @@ * * @author Juliette Reinders Folmer * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; -class DoubleArrowTest extends AbstractMethodUnitTest +final class DoubleArrowTest extends AbstractTokenizerTestCase { @@ -29,7 +29,7 @@ class DoubleArrowTest extends AbstractMethodUnitTest */ public function testDoubleArrow($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); $tokenArray = $tokens[$token]; @@ -45,9 +45,9 @@ public function testDoubleArrow($testMarker) * * @see testDoubleArrow() * - * @return array + * @return array> */ - public function dataDoubleArrow() + public static function dataDoubleArrow() { return [ 'simple_long_array' => ['/* testLongArrayArrowSimple */'], @@ -114,7 +114,7 @@ public function dataDoubleArrow() */ public function testMatchArrow($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); $tokenArray = $tokens[$token]; @@ -130,9 +130,9 @@ public function testMatchArrow($testMarker) * * @see testMatchArrow() * - * @return array + * @return array> */ - public function dataMatchArrow() + public static function dataMatchArrow() { return [ 'single_case' => ['/* testMatchArrowSimpleSingleCase */'], @@ -201,7 +201,7 @@ public function dataMatchArrow() */ public function testFnArrow($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); $tokenArray = $tokens[$token]; @@ -217,9 +217,9 @@ public function testFnArrow($testMarker) * * @see testFnArrow() * - * @return array + * @return array> */ - public function dataFnArrow() + public static function dataFnArrow() { return [ 'simple_fn' => ['/* testFnArrowSimple */'], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php new file mode 100644 index 000000000..aa0817a46 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php @@ -0,0 +1,144 @@ + + * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DoubleQuotedStringTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that double quoted strings contain the complete string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent The expected content of the double quoted string. + * + * @dataProvider dataDoubleQuotedString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testDoubleQuotedString($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $target = $this->getTargetToken($testMarker, T_DOUBLE_QUOTED_STRING); + $this->assertSame($expectedContent, $tokens[$target]['content']); + + }//end testDoubleQuotedString() + + + /** + * Data provider. + * + * Type reference: + * 1. Directly embedded variables. + * 2. Braces outside the variable. + * 3. Braces after the dollar sign. + * 4. Variable variables and expressions. + * + * @link https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation + * + * @see testDoubleQuotedString() + * + * @return array> + */ + public static function dataDoubleQuotedString() + { + return [ + 'Type 1: simple variable' => [ + 'testMarker' => '/* testSimple1 */', + 'expectedContent' => '"$foo"', + ], + 'Type 2: simple variable' => [ + 'testMarker' => '/* testSimple2 */', + 'expectedContent' => '"{$foo}"', + ], + 'Type 3: simple variable' => [ + 'testMarker' => '/* testSimple3 */', + 'expectedContent' => '"${foo}"', + ], + 'Type 1: array offset' => [ + 'testMarker' => '/* testDIM1 */', + 'expectedContent' => '"$foo[bar]"', + ], + 'Type 2: array offset' => [ + 'testMarker' => '/* testDIM2 */', + 'expectedContent' => '"{$foo[\'bar\']}"', + ], + 'Type 3: array offset' => [ + 'testMarker' => '/* testDIM3 */', + 'expectedContent' => '"${foo[\'bar\']}"', + ], + 'Type 1: object property' => [ + 'testMarker' => '/* testProperty1 */', + 'expectedContent' => '"$foo->bar"', + ], + 'Type 2: object property' => [ + 'testMarker' => '/* testProperty2 */', + 'expectedContent' => '"{$foo->bar}"', + ], + 'Type 2: object method call' => [ + 'testMarker' => '/* testMethod1 */', + 'expectedContent' => '"{$foo->bar()}"', + ], + 'Type 2: closure function call' => [ + 'testMarker' => '/* testClosure1 */', + 'expectedContent' => '"{$foo()}"', + ], + 'Type 2: chaining various syntaxes' => [ + 'testMarker' => '/* testChain1 */', + 'expectedContent' => '"{$foo[\'bar\']->baz()()}"', + ], + 'Type 4: variable variables' => [ + 'testMarker' => '/* testVariableVar1 */', + 'expectedContent' => '"${$bar}"', + ], + 'Type 4: variable constants' => [ + 'testMarker' => '/* testVariableVar2 */', + 'expectedContent' => '"${(foo)}"', + ], + 'Type 4: object property' => [ + 'testMarker' => '/* testVariableVar3 */', + 'expectedContent' => '"${foo->bar}"', + ], + 'Type 4: variable variable nested in array offset' => [ + 'testMarker' => '/* testNested1 */', + 'expectedContent' => '"${foo["${bar}"]}"', + ], + 'Type 4: variable array offset nested in array offset' => [ + 'testMarker' => '/* testNested2 */', + 'expectedContent' => '"${foo["${bar[\'baz\']}"]}"', + ], + 'Type 4: variable object property' => [ + 'testMarker' => '/* testNested3 */', + 'expectedContent' => '"${foo->{$baz}}"', + ], + 'Type 4: variable object property - complex with single quotes' => [ + 'testMarker' => '/* testNested4 */', + 'expectedContent' => '"${foo->{${\'a\'}}}"', + ], + 'Type 4: variable object property - complex with single and double quotes' => [ + 'testMarker' => '/* testNested5 */', + 'expectedContent' => '"${foo->{"${\'a\'}"}}"', + ], + 'Type 4: live coding/parse error' => [ + 'testMarker' => '/* testParseError */', + 'expectedContent' => '"${foo["${bar +', + ], + ]; + + }//end dataDoubleQuotedString() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.php new file mode 100644 index 000000000..6836ea05e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.php @@ -0,0 +1,150 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class EnumCaseTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the enum "case" is converted to T_ENUM_CASE. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataEnumCases + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testEnumCases($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$enumCase]; + + $this->assertSame(T_ENUM_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (code)'); + $this->assertSame('T_ENUM_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (type)'); + + }//end testEnumCases() + + + /** + * Data provider. + * + * @see testEnumCases() + * + * @return array> + */ + public static function dataEnumCases() + { + return [ + 'enum case, no value' => ['/* testPureEnumCase */'], + 'enum case, integer value' => ['/* testBackingIntegerEnumCase */'], + 'enum case, string value' => ['/* testBackingStringEnumCase */'], + 'enum case, integer value in more complex enum' => ['/* testEnumCaseInComplexEnum */'], + 'enum case, keyword in mixed case' => ['/* testEnumCaseIsCaseInsensitive */'], + 'enum case, after switch statement' => ['/* testEnumCaseAfterSwitch */'], + 'enum case, after switch statement using alternative syntax' => ['/* testEnumCaseAfterSwitchWithEndSwitch */'], + ]; + + }//end dataEnumCases() + + + /** + * Test that "case" that is not enum case is still tokenized as `T_CASE`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataNotEnumCases + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNotEnumCases($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $case = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$case]; + + $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); + $this->assertSame('T_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (type)'); + + }//end testNotEnumCases() + + + /** + * Data provider. + * + * @see testNotEnumCases() + * + * @return array> + */ + public static function dataNotEnumCases() + { + return [ + 'switch case with constant, semicolon condition end' => ['/* testCaseWithSemicolonIsNotEnumCase */'], + 'switch case with constant, colon condition end' => ['/* testCaseWithConstantIsNotEnumCase */'], + 'switch case with constant, comparison' => ['/* testCaseWithConstantAndIdenticalIsNotEnumCase */'], + 'switch case with constant, assignment' => ['/* testCaseWithAssigmentToConstantIsNotEnumCase */'], + 'switch case with constant, keyword in mixed case' => ['/* testIsNotEnumCaseIsCaseInsensitive */'], + 'switch case, body in curlies declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'], + 'switch case, body after semicolon declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'], + ]; + + }//end dataNotEnumCases() + + + /** + * Test that "case" that is not enum case is still tokenized as `T_CASE`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataKeywordAsEnumCaseNameShouldBeString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testKeywordAsEnumCaseNameShouldBeString($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]); + $tokenArray = $tokens[$enumCaseName]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testKeywordAsEnumCaseNameShouldBeString() + + + /** + * Data provider. + * + * @see testKeywordAsEnumCaseNameShouldBeString() + * + * @return array> + */ + public static function dataKeywordAsEnumCaseNameShouldBeString() + { + return [ + '"interface" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], + '"trait" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], + '"enum" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], + '"function" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], + '"false" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString5 */'], + '"default" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString6 */'], + '"array" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString7 */'], + ]; + + }//end dataKeywordAsEnumCaseNameShouldBeString() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php new file mode 100644 index 000000000..e73dde122 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php @@ -0,0 +1,98 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class FinallyTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the finally keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataFinallyKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testFinallyKeyword($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_FINALLY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_FINALLY (code)'); + $this->assertSame('T_FINALLY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_FINALLY (type)'); + + }//end testFinallyKeyword() + + + /** + * Data provider. + * + * @see testFinallyKeyword() + * + * @return array> + */ + public static function dataFinallyKeyword() + { + return [ + 'finally after try and catch' => ['/* testTryCatchFinally */'], + 'finally between try and catch' => ['/* testTryFinallyCatch */'], + 'finally after try, no catch' => ['/* testTryFinally */'], + ]; + + }//end dataFinallyKeyword() + + + /** + * Test that 'finally' when not used as the reserved keyword is tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataFinallyNonKeyword + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testFinallyNonKeyword($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testFinallyNonKeyword() + + + /** + * Data provider. + * + * @see testFinallyNonKeyword() + * + * @return array> + */ + public static function dataFinallyNonKeyword() + { + return [ + 'finally used as class constant name' => ['/* testFinallyUsedAsClassConstantName */'], + 'finally used as method name' => ['/* testFinallyUsedAsMethodName */'], + 'finally used as property name' => ['/* testFinallyUsedAsPropertyName */'], + ]; + + }//end dataFinallyNonKeyword() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc new file mode 100644 index 000000000..249064a23 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc @@ -0,0 +1,85 @@ + +
+ + + +
+ +
+ + property: + // Do something. + break; +} + +switch (true) { + /* testNotGotoDeclarationGlobalConstantInTernary */ + case $x === ($cond) ? CONST_A : CONST_B: + // Do something. + break; +} + +/* testNotGotoDeclarationEnumWithType */ +enum Suit: string implements Colorful, CardGame {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.php new file mode 100644 index 000000000..09bb6fe2f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.php @@ -0,0 +1,194 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the tokenization of goto declarations and statements. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class GotoLabelTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that the label in a goto statement is tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataGotoStatement + * + * @return void + */ + public function testGotoStatement($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, T_STRING); + + $this->assertTrue(is_int($label)); + $this->assertSame($testContent, $tokens[$label]['content']); + + }//end testGotoStatement() + + + /** + * Data provider. + * + * @see testGotoStatement() + * + * @return array> + */ + public static function dataGotoStatement() + { + return [ + 'label for goto statement' => [ + 'testMarker' => '/* testGotoStatement */', + 'testContent' => 'marker', + ], + 'label for goto statement in loop, keyword capitalized' => [ + 'testMarker' => '/* testGotoStatementInLoop */', + 'testContent' => 'end', + ], + 'label for goto statement in switch' => [ + 'testMarker' => '/* testGotoStatementInSwitch */', + 'testContent' => 'def', + ], + 'label for goto statement within function' => [ + 'testMarker' => '/* testGotoStatementInFunction */', + 'testContent' => 'label', + ], + ]; + + }//end dataGotoStatement() + + + /** + * Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataGotoDeclaration + * + * @return void + */ + public function testGotoDeclaration($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, T_GOTO_LABEL); + + $this->assertTrue(is_int($label)); + $this->assertSame($testContent, $tokens[$label]['content']); + + }//end testGotoDeclaration() + + + /** + * Data provider. + * + * @see testGotoDeclaration() + * + * @return array> + */ + public static function dataGotoDeclaration() + { + return [ + 'label in goto declaration - marker' => [ + 'testMarker' => '/* testGotoDeclaration */', + 'testContent' => 'marker:', + ], + 'label in goto declaration - end' => [ + 'testMarker' => '/* testGotoDeclarationOutsideLoop */', + 'testContent' => 'end:', + ], + 'label in goto declaration - def' => [ + 'testMarker' => '/* testGotoDeclarationInSwitch */', + 'testContent' => 'def:', + ], + 'label in goto declaration - label' => [ + 'testMarker' => '/* testGotoDeclarationInFunction */', + 'testContent' => 'label:', + ], + ]; + + }//end dataGotoDeclaration() + + + /** + * Verify that the constant used in a switch - case statement is not confused with a goto label. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to expect. + * + * @dataProvider dataNotAGotoDeclaration + * + * @return void + */ + public function testNotAGotoDeclaration($testMarker, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testNotAGotoDeclaration() + + + /** + * Data provider. + * + * @see testNotAGotoDeclaration() + * + * @return array> + */ + public static function dataNotAGotoDeclaration() + { + return [ + 'not goto label - global constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstant */', + 'testContent' => 'CONSTANT', + ], + 'not goto label - namespaced constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationNamespacedConstant */', + 'testContent' => 'CONSTANT', + ], + 'not goto label - class constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationClassConstant */', + 'testContent' => 'CONSTANT', + ], + 'not goto label - class property use followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationClassProperty */', + 'testContent' => 'property', + ], + 'not goto label - global constant followed by ternary else' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'testContent' => 'CONST_A', + ], + 'not goto label - global constant after ternary else' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'testContent' => 'CONST_B', + ], + 'not goto label - name of backed enum' => [ + 'testMarker' => '/* testNotGotoDeclarationEnumWithType */', + 'testContent' => 'Suit', + ], + ]; + + }//end dataNotAGotoDeclaration() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc new file mode 100644 index 000000000..5041dda15 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc @@ -0,0 +1,39 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests the tokenization for heredoc/nowdoc constructs. + * + * Verifies that: + * - Nowdoc opener/closers are retokenized from `T_[START_|END_]HEREDOC` to `T_[START_|END_]NOWDOC`. + * - The contents of the heredoc/nowdoc is tokenized as `T_HEREDOC`/`T_NOWDOC`. + * - Each line of the contents has its own token, which includes the new line char. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class HeredocNowdocTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify tokenization a heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocSingleLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<< 'Some $var text'."\n"], + [T_END_HEREDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocSingleLine() + + + /** + * Verify tokenization a nowdoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocSingleLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'MARKER'\n"], + [T_NOWDOC => 'Some text'."\n"], + [T_END_NOWDOC => 'MARKER'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocSingleLine() + + + /** + * Verify tokenization a multiline heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocMultiLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<<<"😬"'."\n"], + [T_HEREDOC => 'Lorum ipsum'."\n"], + [T_HEREDOC => 'Some $var text'."\n"], + [T_HEREDOC => 'dolor sit amet'."\n"], + [T_END_HEREDOC => '😬'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocMultiLine() + + + /** + * Verify tokenization a multiline testNowdocSingleLine construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocMultiLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'multi_line'\n"], + [T_NOWDOC => 'Lorum ipsum'."\n"], + [T_NOWDOC => 'Some text'."\n"], + [T_NOWDOC => 'dolor sit amet'."\n"], + [T_END_NOWDOC => 'multi_line'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocMultiLine() + + + /** + * Verify tokenization a multiline heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocEndsOnBlankLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<< 'Lorum ipsum'."\n"], + [T_HEREDOC => 'dolor sit amet'."\n"], + [T_HEREDOC => "\n"], + [T_END_HEREDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocEndsOnBlankLine() + + + /** + * Verify tokenization a multiline testNowdocSingleLine construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocEndsOnBlankLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'EOD'\n"], + [T_NOWDOC => 'Lorum ipsum'."\n"], + [T_NOWDOC => 'dolor sit amet'."\n"], + [T_NOWDOC => "\n"], + [T_END_NOWDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocEndsOnBlankLine() + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array> $expectedSequence The consecutive token constants and their contents to expect. + * + * @return void + */ + private function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++, $sequenceKey++) { + $currentItem = $expectedSequence[$sequenceKey]; + $expectedCode = key($currentItem); + $expectedType = Tokens::tokenName($expectedCode); + $expectedContent = current($currentItem); + $errorMsgSuffix = PHP_EOL.'(StackPtr: '.$i.' | Position in sequence: '.$sequenceKey.' | Expected: '.$expectedType.')'; + + $this->assertSame( + $expectedCode, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedType.' (code)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedType, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedType.' (type)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedContent, + $tokens[$i]['content'], + 'Token content did not match expectations'.$errorMsgSuffix + ); + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc new file mode 100644 index 000000000..d552b1283 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc @@ -0,0 +1,11 @@ +>>>>>> master diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php new file mode 100644 index 000000000..877706fb4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php @@ -0,0 +1,41 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the tokenization for an unclosed heredoc construct. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class HeredocParseErrorTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that a heredoc (and nowdoc) start token is retokenized to T_STRING if no closer is found. + * + * @return void + */ + public function testMergeConflict() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testUnclosedHeredoc */', [T_START_HEREDOC, T_STRING], '<<< HEAD'."\n"); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_START_HEREDOC (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_START_HEREDOC (type)'); + + }//end testMergeConflict() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php new file mode 100644 index 000000000..c31c17538 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php @@ -0,0 +1,161 @@ + + * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class HeredocStringTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that heredoc strings contain the complete interpolated string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent The expected content of the heredoc string. + * + * @dataProvider dataHeredocString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testHeredocString($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $target = $this->getTargetToken($testMarker, T_HEREDOC); + $this->assertSame($expectedContent."\n", $tokens[$target]['content']); + + }//end testHeredocString() + + + /** + * Test that heredoc strings contain the complete interpolated string when combined with other texts. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent The expected content of the heredoc string. + * + * @dataProvider dataHeredocString + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testHeredocStringWrapped($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + + $testMarker = substr($testMarker, 0, -3).'Wrapped */'; + $target = $this->getTargetToken($testMarker, T_HEREDOC); + $this->assertSame('Do '.$expectedContent." Something\n", $tokens[$target]['content']); + + }//end testHeredocStringWrapped() + + + /** + * Data provider. + * + * Type reference: + * 1. Directly embedded variables. + * 2. Braces outside the variable. + * 3. Braces after the dollar sign. + * 4. Variable variables and expressions. + * + * @link https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation + * + * @see testHeredocString() + * + * @return array> + */ + public static function dataHeredocString() + { + return [ + 'Type 1: simple variable' => [ + 'testMarker' => '/* testSimple1 */', + 'expectedContent' => '$foo', + ], + 'Type 2: simple variable' => [ + 'testMarker' => '/* testSimple2 */', + 'expectedContent' => '{$foo}', + ], + 'Type 3: simple variable' => [ + 'testMarker' => '/* testSimple3 */', + 'expectedContent' => '${foo}', + ], + 'Type 1: array offset' => [ + 'testMarker' => '/* testDIM1 */', + 'expectedContent' => '$foo[bar]', + ], + 'Type 2: array offset' => [ + 'testMarker' => '/* testDIM2 */', + 'expectedContent' => '{$foo[\'bar\']}', + ], + 'Type 3: array offset' => [ + 'testMarker' => '/* testDIM3 */', + 'expectedContent' => '${foo[\'bar\']}', + ], + 'Type 1: object property' => [ + 'testMarker' => '/* testProperty1 */', + 'expectedContent' => '$foo->bar', + ], + 'Type 2: object property' => [ + 'testMarker' => '/* testProperty2 */', + 'expectedContent' => '{$foo->bar}', + ], + 'Type 2: object method call' => [ + 'testMarker' => '/* testMethod1 */', + 'expectedContent' => '{$foo->bar()}', + ], + 'Type 2: closure function call' => [ + 'testMarker' => '/* testClosure1 */', + 'expectedContent' => '{$foo()}', + ], + 'Type 2: chaining various syntaxes' => [ + 'testMarker' => '/* testChain1 */', + 'expectedContent' => '{$foo[\'bar\']->baz()()}', + ], + 'Type 4: variable variables' => [ + 'testMarker' => '/* testVariableVar1 */', + 'expectedContent' => '${$bar}', + ], + 'Type 4: variable constants' => [ + 'testMarker' => '/* testVariableVar2 */', + 'expectedContent' => '${(foo)}', + ], + 'Type 4: object property' => [ + 'testMarker' => '/* testVariableVar3 */', + 'expectedContent' => '${foo->bar}', + ], + 'Type 4: variable variable nested in array offset' => [ + 'testMarker' => '/* testNested1 */', + 'expectedContent' => '${foo["${bar}"]}', + ], + 'Type 4: variable array offset nested in array offset' => [ + 'testMarker' => '/* testNested2 */', + 'expectedContent' => '${foo["${bar[\'baz\']}"]}', + ], + 'Type 4: variable object property' => [ + 'testMarker' => '/* testNested3 */', + 'expectedContent' => '${foo->{$baz}}', + ], + 'Type 4: variable object property - complex with single quotes' => [ + 'testMarker' => '/* testNested4 */', + 'expectedContent' => '${foo->{${\'a\'}}}', + ], + 'Type 4: variable object property - complex with single and double quotes' => [ + 'testMarker' => '/* testNested5 */', + 'expectedContent' => '${foo->{"${\'a\'}"}}', + ], + ]; + + }//end dataHeredocString() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc index b9c0df24d..2f1d20bf0 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc @@ -32,13 +32,13 @@ array_fill( value: 50 ); -/* testNamespaceOperatorFunction */ +/* testNamespaceRelativeFunction */ namespace\function_name(label:$string, more: false); -/* testNamespaceRelativeFunction */ +/* testPartiallyQualifiedFunction */ Partially\Qualified\function_name(label:$string, more: false); -/* testNamespacedFQNFunction */ +/* testFullyQualifiedFunction */ \Fully\Qualified\function_name(label: $string, more:false); /* testVariableFunction */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php new file mode 100644 index 000000000..768e41a98 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php @@ -0,0 +1,974 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class NamedFunctionCallArgumentsTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that parameter labels are tokenized as T_PARAM_NAME and that + * the colon after it is tokenized as a T_COLON. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $parameters The token content for each parameter label to look for. + * + * @dataProvider dataNamedFunctionCallArguments + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNamedFunctionCallArguments($testMarker, $parameters) + { + $tokens = $this->phpcsFile->getTokens(); + + foreach ($parameters as $content) { + $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); + + $this->assertSame( + T_PARAM_NAME, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)' + ); + $this->assertSame( + 'T_PARAM_NAME', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)' + ); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + }//end foreach + + }//end testNamedFunctionCallArguments() + + + /** + * Data provider. + * + * @see testNamedFunctionCallArguments() + * + * @return array>> + */ + public static function dataNamedFunctionCallArguments() + { + return [ + 'function call, single line, all named args' => [ + 'testMarker' => '/* testNamedArgs */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call, multi-line, all named args' => [ + 'testMarker' => '/* testNamedArgsMultiline */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call, single line, all named args; comments and whitespace' => [ + 'testMarker' => '/* testNamedArgsWithWhitespaceAndComments */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call, single line, mixed positional and named args' => [ + 'testMarker' => '/* testMixedPositionalAndNamedArgs */', + 'parameters' => [ + 'double_encode', + ], + ], + 'function call containing nested function call values' => [ + 'testMarker' => '/* testNestedFunctionCallOuter */', + 'parameters' => [ + 'start_index', + 'count', + 'value', + ], + ], + 'function call nested in named arg [1]' => [ + 'testMarker' => '/* testNestedFunctionCallInner1 */', + 'parameters' => [ + 'skip', + ], + ], + 'function call nested in named arg [2]' => [ + 'testMarker' => '/* testNestedFunctionCallInner2 */', + 'parameters' => [ + 'array_or_countable', + ], + ], + 'namespace relative function call' => [ + 'testMarker' => '/* testNamespaceRelativeFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'partially qualified function call' => [ + 'testMarker' => '/* testPartiallyQualifiedFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'fully qualified function call' => [ + 'testMarker' => '/* testFullyQualifiedFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'variable function call' => [ + 'testMarker' => '/* testVariableFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'variable variable function call' => [ + 'testMarker' => '/* testVariableVariableFunction */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'method call' => [ + 'testMarker' => '/* testMethodCall */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'variable method call' => [ + 'testMarker' => '/* testVariableMethodCall */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'class instantiation' => [ + 'testMarker' => '/* testClassInstantiation */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'class instantiation with "self"' => [ + 'testMarker' => '/* testClassInstantiationSelf */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'class instantiation with "static"' => [ + 'testMarker' => '/* testClassInstantiationStatic */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'anonymous class instantiation' => [ + 'testMarker' => '/* testAnonClass */', + 'parameters' => [ + 'label', + 'more', + ], + ], + 'function call with non-ascii characters in the variable name labels' => [ + 'testMarker' => '/* testNonAsciiNames */', + 'parameters' => [ + '💩💩💩', + 'Пасха', + '_valid', + ], + ], + + // Coding errors which should still be handled. + 'invalid: named arg before positional (compile error)' => [ + 'testMarker' => '/* testCompileErrorNamedBeforePositional */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: duplicate parameter name [1]' => [ + 'testMarker' => '/* testDuplicateName1 */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: duplicate parameter name [2]' => [ + 'testMarker' => '/* testDuplicateName2 */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: named arg before variadic (error exception)' => [ + 'testMarker' => '/* testIncorrectOrderWithVariadic */', + 'parameters' => [ + 'start_index', + ], + ], + 'invalid: named arg after variadic (compile error)' => [ + 'testMarker' => '/* testCompileErrorIncorrectOrderWithVariadic */', + 'parameters' => [ + 'param', + ], + ], + 'invalid: named arg without value (parse error)' => [ + 'testMarker' => '/* testParseErrorNoValue */', + 'parameters' => [ + 'param1', + 'param2', + ], + ], + 'invalid: named arg in exit() (parse error)' => [ + 'testMarker' => '/* testParseErrorExit */', + 'parameters' => [ + 'status', + ], + ], + 'invalid: named arg in empty() (parse error)' => [ + 'testMarker' => '/* testParseErrorEmpty */', + 'parameters' => [ + 'variable', + ], + ], + 'invalid: named arg in eval() (parse error)' => [ + 'testMarker' => '/* testParseErrorEval */', + 'parameters' => [ + 'code', + ], + ], + 'invalid: named arg in arbitrary parentheses (parse error)' => [ + 'testMarker' => '/* testParseErrorArbitraryParentheses */', + 'parameters' => [ + 'something', + ], + ], + ]; + + }//end dataNamedFunctionCallArguments() + + + /** + * Verify that other T_STRING tokens within a function call are still tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $content The token content to look for. + * + * @dataProvider dataOtherTstringInFunctionCall + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testOtherTstringInFunctionCall($testMarker, $content) + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); + + $this->assertSame( + T_STRING, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (code)' + ); + $this->assertSame( + 'T_STRING', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_STRING (type)' + ); + + }//end testOtherTstringInFunctionCall() + + + /** + * Data provider. + * + * @see testOtherTstringInFunctionCall() + * + * @return array> + */ + public static function dataOtherTstringInFunctionCall() + { + return [ + 'not arg name - global constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'START_INDEX', + ], + 'not arg name - fully qualified constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'COUNT', + ], + 'not arg name - namespace relative constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'VALUE', + ], + 'not arg name - unqualified function call' => [ + 'testMarker' => '/* testNestedFunctionCallInner2 */', + 'content' => 'count', + ], + ]; + + }//end dataOtherTstringInFunctionCall() + + + /** + * Verify whether the colons are tokenized correctly when a ternary is used in a mixed + * positional and named arguments function call. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testMixedPositionalAndNamedArgsWithTernary() + { + $tokens = $this->phpcsFile->getTokens(); + + $true = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_TRUE); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + $label = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_PARAM_NAME, 'name'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testMixedPositionalAndNamedArgsWithTernary() + + + /** + * Verify whether the colons are tokenized correctly when a ternary is used + * in a named arguments function call. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNamedArgWithTernary() + { + $tokens = $this->phpcsFile->getTokens(); + + /* + * First argument. + */ + + $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'label'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'First arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'First arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_TRUE); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'First arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + /* + * Second argument. + */ + + $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'more'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Second arg: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Second arg: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_STRING, 'CONSTANT_A'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Second arg ternary: Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + }//end testNamedArgWithTernary() + + + /** + * Verify whether the colons are tokenized correctly when named arguments + * function calls are used in a ternary. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryWithFunctionCallsInThenElse() + { + $tokens = $this->phpcsFile->getTokens(); + + /* + * Then. + */ + + $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'label'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Function in then: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Function in then: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $closeParens = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_CLOSE_PARENTHESIS); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closeParens + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + /* + * Else. + */ + + $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'more'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Function in else: Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Function in else: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testTernaryWithFunctionCallsInThenElse() + + + /** + * Verify whether the colons are tokenized correctly when constants are used in a ternary. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryWithConstantsInThenElse() + { + $tokens = $this->phpcsFile->getTokens(); + + $constant = $this->getTargetToken('/* testTernaryWithConstantsInThenElse */', T_STRING, 'CONSTANT_NAME'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($constant + 1), null, true); + + $this->assertSame( + T_INLINE_ELSE, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (code)' + ); + $this->assertSame( + 'T_INLINE_ELSE', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_INLINE_ELSE (type)' + ); + + }//end testTernaryWithConstantsInThenElse() + + + /** + * Verify whether the colons are tokenized correctly in a switch statement. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testSwitchStatement() + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken('/* testSwitchCaseWithConstant */', T_STRING, 'MY_CONSTANT'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'First case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $label = $this->getTargetToken('/* testSwitchCaseWithClassProperty */', T_STRING, 'property'); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Second case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + $default = $this->getTargetToken('/* testSwitchDefault */', T_DEFAULT); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($default + 1), null, true); + + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Default case: Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testSwitchStatement() + + + /** + * Verify that a variable parameter label (parse error) is still tokenized as T_VARIABLE. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testParseErrorVariableLabel() + { + $tokens = $this->phpcsFile->getTokens(); + + $label = $this->getTargetToken('/* testParseErrorDynamicName */', [T_VARIABLE, T_PARAM_NAME], '$variableStoringParamName'); + + $this->assertSame( + T_VARIABLE, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (code)' + ); + $this->assertSame( + 'T_VARIABLE', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_VARIABLE (type)' + ); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testParseErrorVariableLabel() + + + /** + * Verify whether the colons are tokenized correctly when a return type is used for an inline + * closure/arrow function declaration in a ternary. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataOtherColonsInTernary + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testOtherColonsInTernary($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $startOfStatement = $this->getTargetToken($testMarker, T_VARIABLE); + + // Walk the statement and check the tokenization. + // There should be no T_PARAM_NAME tokens. + // First colon should be T_COLON for the return type. + // Second colon should be T_INLINE_ELSE for the ternary. + // Third colon should be T_COLON for the return type. + $colonCount = 0; + for ($i = ($startOfStatement + 1); $tokens[$i]['line'] === $tokens[$startOfStatement]['line']; $i++) { + $this->assertNotSame(T_PARAM_NAME, $tokens[$i]['code'], "Token $i is tokenized as parameter label"); + + if ($tokens[$i]['content'] === ':') { + ++$colonCount; + + if ($colonCount === 1) { + $this->assertSame(T_COLON, $tokens[$i]['code'], 'First colon is not tokenized as T_COLON'); + } else if ($colonCount === 2) { + $this->assertSame(T_INLINE_ELSE, $tokens[$i]['code'], 'Second colon is not tokenized as T_INLINE_ELSE'); + } else if ($colonCount === 3) { + $this->assertSame(T_COLON, $tokens[$i]['code'], 'Third colon is not tokenized as T_COLON'); + } else { + $this->fail('Unexpected colon encountered in statement'); + } + } + } + + }//end testOtherColonsInTernary() + + + /** + * Data provider. + * + * @see testOtherColonsInTernary() + * + * @return array> + */ + public static function dataOtherColonsInTernary() + { + return [ + 'closures with return types in ternary' => [ + 'testMarker' => '/* testTernaryWithClosuresAndReturnTypes */', + ], + 'arrow functions with return types in ternary' => [ + 'testMarker' => '/* testTernaryWithArrowFunctionsAndReturnTypes */', + ], + ]; + + }//end dataOtherColonsInTernary() + + + /** + * Verify that reserved keywords used as a parameter label are tokenized as T_PARAM_NAME + * and that the colon after it is tokenized as a T_COLON. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $tokenTypes The token codes to look for. + * @param string $tokenContent The token content to look for. + * + * @dataProvider dataReservedKeywordsAsName + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testReservedKeywordsAsName($testMarker, $tokenTypes, $tokenContent) + { + $tokens = $this->phpcsFile->getTokens(); + $label = $this->getTargetToken($testMarker, $tokenTypes, $tokenContent); + + $this->assertSame( + T_PARAM_NAME, + $tokens[$label]['code'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (code)' + ); + $this->assertSame( + 'T_PARAM_NAME', + $tokens[$label]['type'], + 'Token tokenized as '.$tokens[$label]['type'].', not T_PARAM_NAME (type)' + ); + + // Get the next non-empty token. + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + + $this->assertSame( + ':', + $tokens[$colon]['content'], + 'Next token after parameter name is not a colon. Found: '.$tokens[$colon]['content'] + ); + $this->assertSame( + T_COLON, + $tokens[$colon]['code'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (code)' + ); + $this->assertSame( + 'T_COLON', + $tokens[$colon]['type'], + 'Token tokenized as '.$tokens[$colon]['type'].', not T_COLON (type)' + ); + + }//end testReservedKeywordsAsName() + + + /** + * Data provider. + * + * @see testReservedKeywordsAsName() + * + * @return array>> + */ + public static function dataReservedKeywordsAsName() + { + $reservedKeywords = [ + // '__halt_compiler', NOT TESTABLE + 'abstract', + 'and', + 'array', + 'as', + 'break', + 'callable', + 'case', + 'catch', + 'class', + 'clone', + 'const', + 'continue', + 'declare', + 'default', + 'die', + 'do', + 'echo', + 'else', + 'elseif', + 'empty', + 'enddeclare', + 'endfor', + 'endforeach', + 'endif', + 'endswitch', + 'endwhile', + 'enum', + 'eval', + 'exit', + 'extends', + 'final', + 'finally', + 'fn', + 'for', + 'foreach', + 'function', + 'global', + 'goto', + 'if', + 'implements', + 'include', + 'include_once', + 'instanceof', + 'insteadof', + 'interface', + 'isset', + 'list', + 'match', + 'namespace', + 'new', + 'or', + 'print', + 'private', + 'protected', + 'public', + 'readonly', + 'require', + 'require_once', + 'return', + 'static', + 'switch', + 'throw', + 'trait', + 'try', + 'unset', + 'use', + 'var', + 'while', + 'xor', + 'yield', + 'int', + 'float', + 'bool', + 'string', + 'true', + 'false', + 'null', + 'void', + 'iterable', + 'object', + 'resource', + 'mixed', + 'numeric', + 'never', + + // Not reserved keyword, but do have their own token in PHPCS. + 'parent', + 'self', + ]; + + $data = []; + + foreach ($reservedKeywords as $keyword) { + $tokensTypes = [ + T_PARAM_NAME, + T_STRING, + T_GOTO_LABEL, + ]; + $tokenName = 'T_'.strtoupper($keyword); + + if ($keyword === 'and') { + $tokensTypes[] = T_LOGICAL_AND; + } else if ($keyword === 'die') { + $tokensTypes[] = T_EXIT; + } else if ($keyword === 'or') { + $tokensTypes[] = T_LOGICAL_OR; + } else if ($keyword === 'xor') { + $tokensTypes[] = T_LOGICAL_XOR; + } else if ($keyword === '__halt_compiler') { + $tokensTypes[] = T_HALT_COMPILER; + } else if (defined($tokenName) === true) { + $tokensTypes[] = constant($tokenName); + } + + $data[$keyword.'FirstParam'] = [ + '/* testReservedKeyword'.ucfirst($keyword).'1 */', + $tokensTypes, + $keyword, + ]; + + $data[$keyword.'SecondParam'] = [ + '/* testReservedKeyword'.ucfirst($keyword).'2 */', + $tokensTypes, + $keyword, + ]; + }//end foreach + + return $data; + + }//end dataReservedKeywordsAsName() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc new file mode 100644 index 000000000..4c018af63 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc @@ -0,0 +1,13 @@ +phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_NULLABLE, T_INLINE_THEN]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_NULLABLE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_NULLABLE (code)'); + $this->assertSame('T_NULLABLE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_NULLABLE (type)'); + + }//end testNullable() + + + /** + * Data provider. + * + * @see testNullable() + * + * @return array> + */ + public static function dataNullable() + { + return [ + 'property declaration, readonly, no visibility' => ['/* testNullableReadonlyOnly */'], + ]; + + }//end dataNullable() + + + /** + * Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataInlineThen + * + * @return void + */ + public function testInlineThen($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_NULLABLE, T_INLINE_THEN]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_INLINE_THEN, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_INLINE_THEN (code)'); + $this->assertSame('T_INLINE_THEN', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_INLINE_THEN (type)'); + + }//end testInlineThen() + + + /** + * Data provider. + * + * @see testInlineThen() + * + * @return array> + */ + public static function dataInlineThen() + { + return [ + 'ternary in property default value' => ['/* testInlineThenInPropertyDefaultValue */'], + ]; + + }//end dataInlineThen() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php new file mode 100644 index 000000000..368fee4db --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php @@ -0,0 +1,144 @@ += 8.0 nullsafe object operator. + * + * @author Juliette Reinders Folmer + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class NullsafeObjectOperatorTest extends AbstractTokenizerTestCase +{ + + /** + * Tokens to search for. + * + * @var array + */ + protected $find = [ + T_NULLSAFE_OBJECT_OPERATOR, + T_OBJECT_OPERATOR, + T_INLINE_THEN, + ]; + + + /** + * Test that a normal object operator is still tokenized as such. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testObjectOperator() + { + $tokens = $this->phpcsFile->getTokens(); + + $operator = $this->getTargetToken('/* testObjectOperator */', $this->find); + $this->assertSame(T_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is object operator'); + $this->assertSame('T_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is object operator'); + + }//end testObjectOperator() + + + /** + * Test that a nullsafe object operator is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataNullsafeObjectOperator + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testNullsafeObjectOperator($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $operator = $this->getTargetToken($testMarker, $this->find); + $this->assertSame(T_NULLSAFE_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is nullsafe object operator'); + $this->assertSame('T_NULLSAFE_OBJECT_OPERATOR', $tokens[$operator]['type'], 'Failed asserting type is nullsafe object operator'); + + }//end testNullsafeObjectOperator() + + + /** + * Data provider. + * + * @see testNullsafeObjectOperator() + * + * @return array> + */ + public static function dataNullsafeObjectOperator() + { + return [ + 'nullsafe operator' => ['/* testNullsafeObjectOperator */'], + 'illegal nullsafe operator (write context)' => ['/* testNullsafeObjectOperatorWriteContext */'], + ]; + + }//end dataNullsafeObjectOperator() + + + /** + * Test that a question mark not followed by an object operator is tokenized as T_TERNARY_THEN. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $testObjectOperator Whether to test for the next non-empty token being tokenized + * as an object operator. + * + * @dataProvider dataTernaryThen + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryThen($testMarker, $testObjectOperator=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $operator = $this->getTargetToken($testMarker, $this->find); + $this->assertSame(T_INLINE_THEN, $tokens[$operator]['code'], 'Failed asserting code is inline then'); + $this->assertSame('T_INLINE_THEN', $tokens[$operator]['type'], 'Failed asserting type is inline then'); + + if ($testObjectOperator === true) { + $next = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($operator + 1), null, true); + $this->assertSame(T_OBJECT_OPERATOR, $tokens[$next]['code'], 'Failed asserting code is object operator'); + $this->assertSame('T_OBJECT_OPERATOR', $tokens[$next]['type'], 'Failed asserting type is object operator'); + } + + }//end testTernaryThen() + + + /** + * Data provider. + * + * @see testTernaryThen() + * + * @return array> + */ + public static function dataTernaryThen() + { + return [ + 'ternary then' => [ + 'testMarker' => '/* testTernaryThen */', + ], + 'whitespace between question mark and object operator' => [ + 'testMarker' => '/* testParseErrorWhitespaceNotAllowed */', + 'testObjectOperator' => true, + ], + 'comment between question mark and object operator' => [ + 'testMarker' => '/* testParseErrorCommentNotAllowed */', + 'testObjectOperator' => true, + ], + 'parse error/live coding' => [ + 'testMarker' => '/* testLiveCoding */', + ], + ]; + + }//end dataTernaryThen() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc new file mode 100644 index 000000000..028592f76 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc @@ -0,0 +1,247 @@ + $param->get(); + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php new file mode 100644 index 000000000..35c899714 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php @@ -0,0 +1,721 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the conversion of PHPCS native context sensitive keyword tokens to T_STRING. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::standardiseToken + */ +final class OtherContextSensitiveKeywordsTest extends AbstractTokenizerTestCase +{ + + + /** + * Clear the "resolved tokens" cache before running this test as otherwise the code + * under test may not be run during the test. + * + * @beforeClass + * + * @return void + */ + public static function clearTokenCache() + { + parent::clearResolvedTokensCache(); + + }//end clearTokenCache() + + + /** + * Test that context sensitive keyword is tokenized as string when it should be string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataStrings + * + * @return void + */ + public function testStrings($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testStrings() + + + /** + * Data provider. + * + * @see testStrings() + * + * @return array> + */ + public static function dataStrings() + { + return [ + 'constant declaration: parent' => ['/* testParent */'], + 'constant declaration: self' => ['/* testSelf */'], + 'constant declaration: false' => ['/* testFalse */'], + 'constant declaration: true' => ['/* testTrue */'], + 'constant declaration: null' => ['/* testNull */'], + + 'function declaration with return by ref: self' => ['/* testKeywordSelfAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: parent' => ['/* testKeywordParentAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: false' => ['/* testKeywordFalseAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: true' => ['/* testKeywordTrueAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: null' => ['/* testKeywordNullAfterFunctionByRefShouldBeString */'], + + 'function call: self' => ['/* testKeywordAsFunctionCallNameShouldBeStringSelf */'], + 'function call: parent' => ['/* testKeywordAsFunctionCallNameShouldBeStringParent */'], + 'function call: false' => ['/* testKeywordAsFunctionCallNameShouldBeStringFalse */'], + 'function call: true' => ['/* testKeywordAsFunctionCallNameShouldBeStringTrue */'], + 'function call: null; with comment between keyword and parentheses' => ['/* testKeywordAsFunctionCallNameShouldBeStringNull */'], + + 'class instantiation: false' => ['/* testClassInstantiationFalseIsString */'], + 'class instantiation: true' => ['/* testClassInstantiationTrueIsString */'], + 'class instantiation: null' => ['/* testClassInstantiationNullIsString */'], + + 'constant declaration: false as name after type' => ['/* testFalseIsNameForTypedConstant */'], + 'constant declaration: true as name after type' => ['/* testTrueIsNameForTypedConstant */'], + 'constant declaration: null as name after type' => ['/* testNullIsNameForTypedConstant */'], + 'constant declaration: self as name after type' => ['/* testSelfIsNameForTypedConstant */'], + 'constant declaration: parent as name after type' => ['/* testParentIsNameForTypedConstant */'], + ]; + + }//end dataStrings() + + + /** + * Test that context sensitive keyword is tokenized as keyword when it should be keyword. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedTokenType The expected token type. + * + * @dataProvider dataKeywords + * + * @return void + */ + public function testKeywords($testMarker, $expectedTokenType) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame( + constant($expectedTokenType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' + ); + $this->assertSame( + $expectedTokenType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' + ); + + }//end testKeywords() + + + /** + * Data provider. + * + * @see testKeywords() + * + * @return array> + */ + public static function dataKeywords() + { + return [ + 'self: param type declaration' => [ + 'testMarker' => '/* testSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: param type declaration' => [ + 'testMarker' => '/* testParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'parent: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + + 'false: param type declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: param type declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: param type declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: return type declaration in union' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: return type declaration in union' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: return type declaration in union' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: in comparison' => [ + 'testMarker' => '/* testFalseIsKeywordInComparison */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: in comparison' => [ + 'testMarker' => '/* testTrueIsKeywordInComparison */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: in comparison' => [ + 'testMarker' => '/* testNullIsKeywordInComparison */', + 'expectedTokenType' => 'T_NULL', + ], + + 'false: type in OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: type in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in function param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'false: DNF type in function return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in function param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'true: DNF type in function return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in function param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'null: DNF type in function return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in function param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'self: DNF type in function return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in function param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + 'parent: DNF type in function return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + ]; + + }//end dataKeywords() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc new file mode 100644 index 000000000..2244b3891 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileSpaceNoNewLine */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc new file mode 100644 index 000000000..191bdae16 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileNoSpaceNoNewLine */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc new file mode 100644 index 000000000..583314db3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileNoSpaceNoNewLineUppercase */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc new file mode 100644 index 000000000..d7383d8e6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc @@ -0,0 +1,51 @@ + $var; + +/* testBooleanNot */ +$a = ! $var; + +/* testComma */ +echo $a, $b, $c; + +/* testAsperand */ +$a = @callMe(); + +/* testDollarAndCurlies */ +echo ${$var}; + +/* testBacktick */ +$a = `ls -e`; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php new file mode 100644 index 000000000..06a130c24 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php @@ -0,0 +1,433 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests that simple tokens are assigned the correct token type and code. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::resolveSimpleToken + */ +final class ResolveSimpleTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Clear the "resolved tokens" cache before running this test as otherwise the code + * under test may not be run during the test. + * + * @beforeClass + * + * @return void + */ + public static function clearTokenCache() + { + parent::clearResolvedTokensCache(); + + }//end clearTokenCache() + + + /** + * Verify tokenization of parentheses, square brackets, curly brackets and a switch colon. + * + * @return void + */ + public function testBracesAndColon() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_VARIABLE, + T_OPEN_SQUARE_BRACKET, + T_LNUMBER, + T_CLOSE_SQUARE_BRACKET, + T_CLOSE_PARENTHESIS, + T_OPEN_CURLY_BRACKET, + T_CASE, + T_STRING, + T_COLON, + T_BREAK, + T_SEMICOLON, + T_CLOSE_CURLY_BRACKET, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_SWITCH); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBracesAndColon() + + + /** + * Verify tokenization of colon after named parameter. + * + * @return void + */ + public function testNamedParamColon() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_PARAM_NAME, + T_COLON, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_STRING); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testNamedParamColon() + + + /** + * Verify tokenization of colon for a return type. + * + * @return void + */ + public function testReturnTypeColon() + { + $expectedSequence = [ + T_EQUAL, + T_CLOSURE, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_COLON, + T_STRING, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testReturnTypeColon() + + + /** + * Verify tokenization of a concatenation operator. + * + * @return void + */ + public function testConcat() + { + $expectedSequence = [ + T_STRING_CONCAT, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CONSTANT_ENCAPSED_STRING); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testConcat() + + + /** + * Verify tokenization of simple math operators. + * + * @return void + */ + public function testSimpleMathTokens() + { + $expectedSequence = [ + T_EQUAL, + T_LNUMBER, + T_MULTIPLY, + T_LNUMBER, + T_DIVIDE, + T_LNUMBER, + T_PLUS, + T_LNUMBER, + T_MINUS, + T_LNUMBER, + T_MODULUS, + T_LNUMBER, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testSimpleMathTokens() + + + /** + * Verify tokenization of unary plus/minus operators. + * + * @return void + */ + public function testUnaryPlusMinus() + { + $expectedSequence = [ + T_EQUAL, + T_PLUS, + T_LNUMBER, + T_DIVIDE, + T_MINUS, + T_LNUMBER, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testUnaryPlusMinus() + + + /** + * Verify tokenization of bitwise operator tokens. + * + * @return void + */ + public function testBitwiseTokens() + { + $expectedSequence = [ + T_EQUAL, + T_STRING, + T_BITWISE_XOR, + T_STRING, + T_BITWISE_AND, + T_STRING, + T_BITWISE_OR, + T_STRING, + T_BITWISE_NOT, + T_STRING, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBitwiseTokens() + + + /** + * Verify tokenization of bitwise operator tokens. + * + * @return void + */ + public function testBitwiseOrInCatch() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_STRING, + T_BITWISE_OR, + T_STRING, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CATCH); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBitwiseOrInCatch() + + + /** + * Verify tokenization of a less than operator. + * + * @return void + */ + public function testLessThan() + { + $expectedSequence = [ + T_LESS_THAN, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testLessThan() + + + /** + * Verify tokenization of a greater than operator. + * + * @return void + */ + public function testGreaterThan() + { + $expectedSequence = [ + T_GREATER_THAN, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testGreaterThan() + + + /** + * Verify tokenization of a boolean not operator. + * + * @return void + */ + public function testBooleanNot() + { + $expectedSequence = [ + T_BOOLEAN_NOT, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBooleanNot() + + + /** + * Verify tokenization of commas. + * + * @return void + */ + public function testComma() + { + $expectedSequence = [ + T_COMMA, + T_VARIABLE, + T_COMMA, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testComma() + + + /** + * Verify tokenization of the silence operator. + * + * @return void + */ + public function testAsperand() + { + $expectedSequence = [ + T_ASPERAND, + T_STRING, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testAsperand() + + + /** + * Verify tokenization of the dollar token and curlies for a variable variable. + * + * @return void + */ + public function testDollarAndCurlies() + { + $expectedSequence = [ + T_DOLLAR, + T_OPEN_CURLY_BRACKET, + T_VARIABLE, + T_CLOSE_CURLY_BRACKET, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_ECHO); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testDollarAndCurlies() + + + /** + * Verify tokenization of the backtick operator. + * + * @return void + */ + public function testBacktick() + { + $expectedSequence = [ + T_BACKTICK, + T_ENCAPSED_AND_WHITESPACE, + T_BACKTICK, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBacktick() + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array $expectedSequence The consecutive token constants to expect. + * + * @return void + */ + private function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those for these tests. + continue; + } + + $expectedTokenName = Tokens::tokenName($expectedSequence[$sequenceKey]); + + $this->assertSame( + $expectedSequence[$sequenceKey], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedTokenName.' (code)' + ); + + $this->assertSame( + $expectedTokenName, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedTokenName.' (type)' + ); + + ++$sequenceKey; + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php new file mode 100644 index 000000000..da9c7c104 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php @@ -0,0 +1,141 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class ShortArrayTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that real square brackets are still tokenized as square brackets. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataSquareBrackets + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testSquareBrackets($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); + $tokenArray = $tokens[$opener]; + + $this->assertSame(T_OPEN_SQUARE_BRACKET, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SQUARE_BRACKET (code)'); + $this->assertSame('T_OPEN_SQUARE_BRACKET', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SQUARE_BRACKET (type)'); + + if (isset($tokens[$opener]['bracket_closer']) === true) { + $closer = $tokens[$opener]['bracket_closer']; + $tokenArray = $tokens[$closer]; + + $this->assertSame(T_CLOSE_SQUARE_BRACKET, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SQUARE_BRACKET (code)'); + $this->assertSame('T_CLOSE_SQUARE_BRACKET', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SQUARE_BRACKET (type)'); + } + + }//end testSquareBrackets() + + + /** + * Data provider. + * + * @see testSquareBrackets() + * + * @return array> + */ + public static function dataSquareBrackets() + { + return [ + 'array access 1' => ['/* testArrayAccess1 */'], + 'array access 2' => ['/* testArrayAccess2 */'], + 'array assignment' => ['/* testArrayAssignment */'], + 'function call dereferencing' => ['/* testFunctionCallDereferencing */'], + 'method call dereferencing' => ['/* testMethodCallDereferencing */'], + 'static method call dereferencing' => ['/* testStaticMethodCallDereferencing */'], + 'property dereferencing' => ['/* testPropertyDereferencing */'], + 'property dereferencing with inaccessable name' => ['/* testPropertyDereferencingWithInaccessibleName */'], + 'static property dereferencing' => ['/* testStaticPropertyDereferencing */'], + 'string dereferencing single quotes' => ['/* testStringDereferencing */'], + 'string dereferencing double quotes' => ['/* testStringDereferencingDoubleQuoted */'], + 'global constant dereferencing' => ['/* testConstantDereferencing */'], + 'class constant dereferencing' => ['/* testClassConstantDereferencing */'], + 'magic constant dereferencing' => ['/* testMagicConstantDereferencing */'], + 'array access with curly braces' => ['/* testArrayAccessCurlyBraces */'], + 'array literal dereferencing' => ['/* testArrayLiteralDereferencing */'], + 'short array literal dereferencing' => ['/* testShortArrayLiteralDereferencing */'], + 'class member dereferencing on instantiation 1' => ['/* testClassMemberDereferencingOnInstantiation1 */'], + 'class member dereferencing on instantiation 2' => ['/* testClassMemberDereferencingOnInstantiation2 */'], + 'class member dereferencing on clone' => ['/* testClassMemberDereferencingOnClone */'], + 'nullsafe method call dereferencing' => ['/* testNullsafeMethodCallDereferencing */'], + 'interpolated string dereferencing' => ['/* testInterpolatedStringDereferencing */'], + 'live coding' => ['/* testLiveCoding */'], + ]; + + }//end dataSquareBrackets() + + + /** + * Test that short arrays and short lists are still tokenized as short arrays. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataShortArrays + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testShortArrays($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); + $tokenArray = $tokens[$opener]; + + $this->assertSame(T_OPEN_SHORT_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SHORT_ARRAY (code)'); + $this->assertSame('T_OPEN_SHORT_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SHORT_ARRAY (type)'); + + if (isset($tokens[$opener]['bracket_closer']) === true) { + $closer = $tokens[$opener]['bracket_closer']; + $tokenArray = $tokens[$closer]; + + $this->assertSame(T_CLOSE_SHORT_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SHORT_ARRAY (code)'); + $this->assertSame('T_CLOSE_SHORT_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SHORT_ARRAY (type)'); + } + + }//end testShortArrays() + + + /** + * Data provider. + * + * @see testShortArrays() + * + * @return array> + */ + public static function dataShortArrays() + { + return [ + 'short array empty' => ['/* testShortArrayDeclarationEmpty */'], + 'short array with value' => ['/* testShortArrayDeclarationWithOneValue */'], + 'short array with values' => ['/* testShortArrayDeclarationWithMultipleValues */'], + 'short array with dereferencing' => ['/* testShortArrayDeclarationWithDereferencing */'], + 'short list' => ['/* testShortListDeclaration */'], + 'short list nested' => ['/* testNestedListDeclaration */'], + 'short array within function call' => ['/* testArrayWithinFunctionCall */'], + 'short list after braced control structure' => ['/* testShortListDeclarationAfterBracedControlStructure */'], + 'short list after non-braced control structure' => ['/* testShortListDeclarationAfterNonBracedControlStructure */'], + 'short list after alternative control structure' => ['/* testShortListDeclarationAfterAlternativeControlStructure */'], + ]; + + }//end dataShortArrays() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.php similarity index 81% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.php index 389bb74e6..ad7d9ceb3 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.php @@ -10,23 +10,23 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; -class StableCommentWhitespaceTest extends AbstractMethodUnitTest +final class StableCommentWhitespaceTest extends AbstractTokenizerTestCase { /** * Test that comment tokenization with new lines at the end of the comment is stable. * - * @param string $testMarker The comment prefacing the test. - * @param array $expectedTokens The tokenization expected. + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. * * @dataProvider dataCommentTokenization * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -35,12 +35,20 @@ class StableCommentWhitespaceTest extends AbstractMethodUnitTest */ public function testCommentTokenization($testMarker, $expectedTokens) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); - foreach ($expectedTokens as $key => $tokenInfo) { - $this->assertSame(constant($tokenInfo['type']), $tokens[$comment]['code']); - $this->assertSame($tokenInfo['type'], $tokens[$comment]['type']); + foreach ($expectedTokens as $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$comment]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$comment]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$comment]['type'], + 'Token tokenized as '.$tokens[$comment]['type'].', not '.$tokenInfo['type'].' (type)' + ); $this->assertSame($tokenInfo['content'], $tokens[$comment]['content']); ++$comment; @@ -54,14 +62,14 @@ public function testCommentTokenization($testMarker, $expectedTokens) * * @see testCommentTokenization() * - * @return array + * @return array>>> */ - public function dataCommentTokenization() + public static function dataCommentTokenization() { return [ - [ - '/* testSingleLineSlashComment */', - [ + 'slash comment, single line' => [ + 'testMarker' => '/* testSingleLineSlashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment @@ -74,9 +82,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashCommentTrailing */', - [ + 'slash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineSlashCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment @@ -89,9 +97,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashAnnotation */', - [ + 'slash ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineSlashAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_DISABLE', 'content' => '// phpcs:disable Stnd.Cat @@ -104,9 +112,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashComment */', - [ + 'slash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineSlashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -129,9 +137,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithIndent */', - [ + 'slash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -162,9 +170,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationStart */', - [ + 'slash comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationStart */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_IGNORE', 'content' => '// phpcs:ignore Stnd.Cat @@ -187,9 +195,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationMiddle */', - [ + 'slash comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationMiddle */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -212,9 +220,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationEnd */', - [ + 'slash comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -237,9 +245,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineStarComment */', - [ + 'star comment, single line' => [ + 'testMarker' => '/* testSingleLineStarComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Single line star comment */', @@ -251,9 +259,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineStarCommentTrailing */', - [ + 'star comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineStarCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment */', @@ -265,9 +273,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineStarAnnotation */', - [ + 'star ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineStarAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_IGNORE', 'content' => '/* phpcs:ignore Stnd.Cat */', @@ -279,9 +287,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarComment */', - [ + 'star comment, multi-line' => [ + 'testMarker' => '/* testMultiLineStarComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -303,9 +311,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithIndent */', - [ + 'star comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineStarCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -327,9 +335,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithAnnotationStart */', - [ + 'star comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationStart */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_IGNORE', 'content' => '/* @phpcs:ignore Stnd.Cat @@ -351,9 +359,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithAnnotationMiddle */', - [ + 'star comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationMiddle */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -375,9 +383,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithAnnotationEnd */', - [ + 'star comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -400,9 +408,9 @@ public function dataCommentTokenization() ], ], - [ - '/* testSingleLineDocblockComment */', - [ + 'docblock comment, single line' => [ + 'testMarker' => '/* testSingleLineDocblockComment */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -426,9 +434,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineDocblockCommentTrailing */', - [ + 'docblock comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineDocblockCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -452,9 +460,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineDocblockAnnotation */', - [ + 'docblock ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineDocblockAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -479,9 +487,9 @@ public function dataCommentTokenization() ], ], - [ - '/* testMultiLineDocblockComment */', - [ + 'docblock comment, multi-line' => [ + 'testMarker' => '/* testMultiLineDocblockComment */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -590,9 +598,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineDocblockCommentWithIndent */', - [ + 'docblock comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -701,9 +709,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineDocblockCommentWithAnnotation */', - [ + 'docblock comment, multi-line, ignore annotation' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -812,9 +820,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineDocblockCommentWithTagAnnotation */', - [ + 'docblock comment, multi-line, ignore annotation as tag' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithTagAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -923,9 +931,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashComment */', - [ + 'hash comment, single line' => [ + 'testMarker' => '/* testSingleLineHashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment @@ -938,9 +946,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashCommentTrailing */', - [ + 'hash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineHashCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment @@ -953,9 +961,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineHashComment */', - [ + 'hash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineHashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment1 @@ -978,9 +986,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineHashCommentWithIndent */', - [ + 'hash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineHashCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment1 @@ -1011,9 +1019,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashCommentNoNewLineAtEnd */', - [ + 'slash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineSlashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Slash ', @@ -1025,9 +1033,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashCommentNoNewLineAtEnd */', - [ + 'hash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineHashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Hash ', @@ -1039,9 +1047,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testCommentAtEndOfFile */', - [ + 'unclosed star comment at end of file' => [ + 'testMarker' => '/* testCommentAtEndOfFile */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.php new file mode 100644 index 000000000..875b666d5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.php @@ -0,0 +1,375 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class StableCommentWhitespaceWinTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that comment tokenization with new lines at the end of the comment is stable. + * + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. + * + * @dataProvider dataCommentTokenization + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testCommentTokenization($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); + + foreach ($expectedTokens as $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$comment]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$comment]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$comment]['type'], + 'Token tokenized as '.$tokens[$comment]['type'].', not '.$tokenInfo['type'].' (type)' + ); + $this->assertSame($tokenInfo['content'], $tokens[$comment]['content']); + + ++$comment; + } + + }//end testCommentTokenization() + + + /** + * Data provider. + * + * @see testCommentTokenization() + * + * @return array>>> + */ + public static function dataCommentTokenization() + { + return [ + 'slash comment, single line' => [ + 'testMarker' => '/* testSingleLineSlashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineSlashCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineSlashAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_DISABLE', + 'content' => '// phpcs:disable Stnd.Cat +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineSlashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationStart */', + 'expectedTokens' => [ + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationMiddle */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// @phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// Comment2 +', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'slash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineSlashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '// Slash ', + ], + [ + 'type' => 'T_CLOSE_TAG', + 'content' => '?> +', + ], + ], + ], + 'hash comment, single line' => [ + 'testMarker' => '/* testSingleLineHashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineHashCommentTrailing */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineHashComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment2 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineHashCommentWithIndent */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment1 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment2 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '# Comment3 +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'hash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineHashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '# Hash ', + ], + [ + 'type' => 'T_CLOSE_TAG', + 'content' => '?> +', + ], + ], + ], + 'unclosed star comment at end of file' => [ + 'testMarker' => '/* testCommentAtEndOfFile */', + 'expectedTokens' => [ + [ + 'type' => 'T_COMMENT', + 'content' => '/* Comment', + ], + ], + ], + ]; + + }//end dataCommentTokenization() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc new file mode 100644 index 000000000..fadc0df85 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc @@ -0,0 +1,167 @@ + $param & $int; + +/* testTypeIntersectionArrowReturnType */ +$arrowWithReturnType = fn ($param) : Foo&Bar => $param * 10; + +/* testBitwiseAndInArrayKey */ +$array = array( + A & B => /* testBitwiseAndInArrayValue */ B & C +); + +/* testBitwiseAndInShortArrayKey */ +$array = [ + A & B => /* testBitwiseAndInShortArrayValue */ B & C +]; + +/* testBitwiseAndNonArrowFnFunctionCall */ +$obj->fn($something & $else); + +/* testBitwiseAnd6 */ +function &fn(/* testTypeIntersectionNonArrowFunctionDeclaration */ Foo&Bar $something) {} + +/* testTypeIntersectionWithInvalidTypes */ +function (int&string $var) {}; + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +return function( Foo& diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php new file mode 100644 index 000000000..b191d7ebd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php @@ -0,0 +1,159 @@ + + * @author Jaroslav Hanslík + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class TypeIntersectionTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that non-intersection type bitwise and tokens are still tokenized as bitwise and. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataBitwiseAnd + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBitwiseAnd($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_BITWISE_AND, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_AND (type)'); + + }//end testBitwiseAnd() + + + /** + * Data provider. + * + * @see testBitwiseAnd() + * + * @return array> + */ + public static function dataBitwiseAnd() + { + return [ + 'in simple assignment 1' => ['/* testBitwiseAnd1 */'], + 'in simple assignment 2' => ['/* testBitwiseAnd2 */'], + 'in OO constant default value' => ['/* testBitwiseAndOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseAndPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseAndParamDefaultValue */'], + 'reference for method parameter' => ['/* testBitwiseAnd3 */'], + 'in return statement' => ['/* testBitwiseAnd4 */'], + 'reference for function parameter' => ['/* testBitwiseAnd5 */'], + 'in OO constant default value DNF-like' => ['/* testBitwiseAndOOConstDefaultValueDNF */'], + 'in property default value DNF-like' => ['/* testBitwiseAndPropertyDefaultValueDNF */'], + 'in method parameter default value DNF-like' => ['/* testBitwiseAndParamDefaultValueDNF */'], + 'in closure parameter default value' => ['/* testBitwiseAndClosureParamDefault */'], + 'in arrow function parameter default value' => ['/* testBitwiseAndArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseAndArrowExpression */'], + 'in long array key' => ['/* testBitwiseAndInArrayKey */'], + 'in long array value' => ['/* testBitwiseAndInArrayValue */'], + 'in short array key' => ['/* testBitwiseAndInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseAndInShortArrayValue */'], + 'in parameter in function call' => ['/* testBitwiseAndNonArrowFnFunctionCall */'], + 'function return by reference' => ['/* testBitwiseAnd6 */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], + ]; + + }//end dataBitwiseAnd() + + + /** + * Test that bitwise and tokens when used as part of a intersection type are tokenized as `T_TYPE_INTERSECTION`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataTypeIntersection + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTypeIntersection($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_TYPE_INTERSECTION, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_INTERSECTION (code)'); + $this->assertSame('T_TYPE_INTERSECTION', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_INTERSECTION (type)'); + + }//end testTypeIntersection() + + + /** + * Data provider. + * + * @see testTypeIntersection() + * + * @return array> + */ + public static function dataTypeIntersection() + { + return [ + 'type for OO constant' => ['/* testTypeIntersectionOOConstSimple */'], + 'type for OO constant, reversed modifier order' => ['/* testTypeIntersectionOOConstReverseModifierOrder */'], + 'type for OO constant, first of multi-intersect' => ['/* testTypeIntersectionOOConstMulti1 */'], + 'type for OO constant, middle of multi-intersect + comments' => ['/* testTypeIntersectionOOConstMulti2 */'], + 'type for OO constant, last of multi-intersect' => ['/* testTypeIntersectionOOConstMulti3 */'], + 'type for OO constant, using namespace relative names' => ['/* testTypeIntersectionOOConstNamespaceRelative */'], + 'type for OO constant, using partially qualified names' => ['/* testTypeIntersectionOOConstPartiallyQualified */'], + 'type for OO constant, using fully qualified names' => ['/* testTypeIntersectionOOConstFullyQualified */'], + 'type for static property' => ['/* testTypeIntersectionPropertySimple */'], + 'type for static property, reversed modifier order' => ['/* testTypeIntersectionPropertyReverseModifierOrder */'], + 'type for property, first of multi-intersect' => ['/* testTypeIntersectionPropertyMulti1 */'], + 'type for property, middle of multi-intersect, also comments' => ['/* testTypeIntersectionPropertyMulti2 */'], + 'type for property, last of multi-intersect' => ['/* testTypeIntersectionPropertyMulti3 */'], + 'type for property using namespace relative names' => ['/* testTypeIntersectionPropertyNamespaceRelative */'], + 'type for property using partially qualified names' => ['/* testTypeIntersectionPropertyPartiallyQualified */'], + 'type for property using fully qualified names' => ['/* testTypeIntersectionPropertyFullyQualified */'], + 'type for readonly property' => ['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'], + 'type for static readonly property' => ['/* testTypeIntersectionPropertyWithStaticKeyword */'], + 'type for final property' => ['/* testTypeIntersectionWithPHP84FinalKeyword */'], + 'type for final property reversed modifier order' => ['/* testTypeIntersectionWithPHP84FinalKeywordFirst */'], + 'type for method parameter' => ['/* testTypeIntersectionParam1 */'], + 'type for method parameter, first in multi-intersect' => ['/* testTypeIntersectionParam2 */'], + 'type for method parameter, last in multi-intersect' => ['/* testTypeIntersectionParam3 */'], + 'type for method parameter with namespace relative names' => ['/* testTypeIntersectionParamNamespaceRelative */'], + 'type for method parameter with partially qualified names' => ['/* testTypeIntersectionParamPartiallyQualified */'], + 'type for method parameter with fully qualified names' => ['/* testTypeIntersectionParamFullyQualified */'], + 'type for property in constructor property promotion' => ['/* testTypeIntersectionConstructorPropertyPromotion */'], + 'return type for method' => ['/* testTypeIntersectionReturnType */'], + 'return type for method, first of multi-intersect' => ['/* testTypeIntersectionAbstractMethodReturnType1 */'], + 'return type for method, last of multi-intersect' => ['/* testTypeIntersectionAbstractMethodReturnType2 */'], + 'return type for method with namespace relative names' => ['/* testTypeIntersectionReturnTypeNamespaceRelative */'], + 'return type for method with partially qualified names' => ['/* testTypeIntersectionReturnPartiallyQualified */'], + 'return type for method with fully qualified names' => ['/* testTypeIntersectionReturnFullyQualified */'], + 'type for function parameter with reference' => ['/* testTypeIntersectionWithReference */'], + 'type for function parameter with spread operator' => ['/* testTypeIntersectionWithSpreadOperator */'], + 'DNF type for OO constant, union before DNF' => ['/* testTypeIntersectionConstantTypeUnionBeforeDNF */'], + 'DNF type for property, union after DNF' => ['/* testTypeIntersectionPropertyTypeUnionAfterDNF */'], + 'DNF type for function param, union before and after DNF' => ['/* testTypeIntersectionParamUnionBeforeAndAfterDNF */'], + 'DNF type for function return, union after DNF with null' => ['/* testTypeIntersectionReturnTypeUnionAfterDNF */'], + 'type for closure parameter with illegal nullable' => ['/* testTypeIntersectionClosureParamIllegalNullable */'], + 'return type for closure' => ['/* testTypeIntersectionClosureReturn */'], + 'type for arrow function parameter' => ['/* testTypeIntersectionArrowParam */'], + 'return type for arrow function' => ['/* testTypeIntersectionArrowReturnType */'], + 'type for function parameter, return by ref' => ['/* testTypeIntersectionNonArrowFunctionDeclaration */'], + 'type for function parameter with invalid types' => ['/* testTypeIntersectionWithInvalidTypes */'], + ]; + + }//end dataTypeIntersection() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc new file mode 100644 index 000000000..4c6212b78 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc @@ -0,0 +1,156 @@ +const ? 0 : 1; + +/* testGlobalConstantCannotBeTyped */ +const GLOBAL_UNTYPED = true; + +/* testGlobalConstantTypedShouldStillBeHandled */ +const ?int GLOBAL_TYPED = true; + +class ClassWithPlainTypedConstants { + /* testClassConstFinalUntyped */ + final const FINAL_UNTYPED = true; + + /* testClassConstVisibilityUntyped */ + public const /*comment*/VISIBLE_UNTYPED = true; + + /* testClassConstTypedTrue */ + const true TYPED_TRUE = true; + /* testClassConstTypedFalse */ + final const false TYPED_FALSE = false; + /* testClassConstTypedNull */ + public const null TYPED_NULL = null; + /* testClassConstTypedBool */ + final protected const/*comment*/bool TYPED_BOOL = false; + /* testClassConstTypedInt */ + private const int TYPED_INT = 0; + /* testClassConstTypedFloat */ + const float TYPED_FLOAT = 0.5; + /* testClassConstTypedString */ + public final const string/*comment*/TYPED_STRING = 'string'; + /* testClassConstTypedArray */ + private final const array TYPED_ARRAY = []; + /* testClassConstTypedObject */ + const + object + TYPED_OBJECT = MyClass::getInstance(); + /* testClassConstTypedIterable */ + const iterable typed_iterable = []; + /* testClassConstTypedMixed */ + const mixed TYPED_MIXED = 'string'; + + /* testClassConstTypedClassUnqualified */ + const MyClass TYPED_UNQUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassFullyQualified */ + public const \MyClass TYPED_FULLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassNamespaceRelative */ + protected const namespace\MyClass TYPED_NAMESPACE_RELATIVE_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassPartiallyQualified */ + private const Partial\MyClass TYPED_PARTIALLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedParent */ + const parent TYPED_PARENT = parent::getInstance(); + + // Illegal types - the fact that these are not allowed in PHP is not the concern of the PHPCS tokenizer. + /* testClassConstTypedCallable */ + protected const callable TYPED_CALLABLE = 'function_name'; + /* testClassConstTypedVoid */ + protected const void TYPED_VOID = null; + /* testClassConstTypedNever */ + protected const NEVER TYPED_NEVER = null; +} + +trait TraitWithNullableTypedConstants { + /* testTraitConstTypedNullableTrue */ + const ?true TYPED_TRUE = true; + /* testTraitConstTypedNullableFalse */ + final const ?false TYPED_FALSE = false; + /* testTraitConstTypedNullableNull */ + public const ?null TYPED_NULL = null; + /* testTraitConstTypedNullableBool */ + final protected const ?bool TYPED_BOOL = false; + /* testTraitConstTypedNullableInt */ + private const ?int TYPED_INT = 0; + /* testTraitConstTypedNullableFloat */ + const ? /*comment*/ float TYPED_FLOAT = 0.5; + /* testTraitConstTypedNullableString */ + public final const ?string TYPED_STRING = 'string'; + /* testTraitConstTypedNullableArray */ + private final const ? array TYPED_ARRAY = []; + /* testTraitConstTypedNullableObject */ + const ?object TYPED_OBJECT = MyClass::getInstance(); + /* testTraitConstTypedNullableIterable */ + const ?iterable TYPED_ITERABLE = []; + /* testTraitConstTypedNullableMixed */ + const ?mixed TYPED_MIXED = 'string'; + + /* testTraitConstTypedNullableClassUnqualified */ + const ?MyClass TYPED_UNQUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassFullyQualified */ + public const ?\MyClass TYPED_FULLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassNamespaceRelative */ + protected const ?namespace\MyClass TYPED_NAMESPACE_RELATIVE_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassPartiallyQualified */ + private const ?Partial\MyClass TYPED_PARTIALLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableParent */ + const ?parent TYPED_PARENT = parent::getInstance(); +} + +interface InterfaceWithUnionTypedConstants { + /* testInterfaceConstTypedUnionTrueNull */ + const true|null /*comment*/ UNION_TRUE_NULL = true; + /* testInterfaceConstTypedUnionArrayObject */ + const array|object UNION_ARRAY_OBJECT = []; + /* testInterfaceConstTypedUnionStringArrayInt */ + const string | array | int UNION_STRING_ARRAY_INT = 'array middle'; + /* testInterfaceConstTypedUnionFloatBoolArray */ + const float /*comment*/| bool|array UNION_FLOAT_BOOL_ARRAY = false; + /* testInterfaceConstTypedUnionIterableFalse */ + const iterable|false UNION_ITERABLE_FALSE = false; + /* testInterfaceConstTypedUnionUnqualifiedNamespaceRelative */ + const Unqualified|namespace\Relative UNION_UNQUALIFIED_NSRELATIVE = new Unqualified(); + /* testInterfaceConstTypedUnionFullyQualifiedPartiallyQualified */ + const \Fully\Qualified|Partially\Qualified UNION_FQN_PARTIAL = new Partial\Qualified; +} + +enum EnumWithIntersectionTypedConstants { + // Illegal types in a class, but legal in an enum. + /* testEnumConstTypedSelf */ + final const self TYPED_SELF = self::getInstance(); + /* testEnumConstTypedStatic */ + const static TYPED_STATIC = static::getInstance(); + /* testEnumConstTypedNullableSelf */ + public const ?self TYPED_SELF = self::getInstance(); + /* testEnumConstTypedNullableStatic */ + const ?static TYPED_STATIC = static::getInstance(); + + /* testEnumConstTypedIntersectUnqualifiedNamespaceRelative */ + const Unqualified&namespace\Relative UNION_UNQUALIFIED_NSRELATIVE = new Unqualified(); + /* testEnumConstTypedIntersectFullyQualifiedPartiallyQualified */ + const \Fully\Qualified&Partially\Qualified UNION_FQN_PARTIAL = new Partial\Qualified; +} + +$anonClassWithDNFTypes = new class() extends Something { + /* testAnonClassConstDNFTypeNullAfter */ + const (A&B)|null DNF_OR_NULL_1 = null; + /* testAnonClassConstDNFTypeNullBefore */ + public final const NULL|(A&B) DNF_OR_NULL_2 = null; + /* testAnonClassConstDNFTypeFalseBefore */ + final const false|(C&D) DNF_OR_FALSE = false; + /* testAnonClassConstDNFTypeTrueAfter */ + private final const ( F & G ) | true DNF_OR_ARRAY = true; + /* testAnonClassConstDNFTypeTrueBeforeFalseAfter */ + public const TRUE|(SplBool&Stringable)|FALSE DNF_OR_BOOL = true; + /* testAnonClassConstDNFTypeArrayAfter */ + final protected const (Traversable&Countable)|array DNF_OR_ARRAY_1 = []; + /* testAnonClassConstDNFTypeArrayBefore */ + private const array /*comment*/ | ( Traversable /*comment*/ & Countable ) DNF_OR_ARRAY_2 = new MyClass; + /* testAnonClassConstDNFTypeInvalidNullable */ + const ? (Invalid&Fatal)|NullableNotAllowed DNF = null; + + /* testAnonClassConstDNFTypeFQNRelativePartiallyQualified */ + const (\FQN&namespace\Relative)|Partially\Qualified DNF_CLASSNAME = MyClass::getInstance(); + /* testAnonClassConstDNFTypeParentSelfStatic */ + const (parent&self)|static DNF_PARENT = parent::getInstance(); +}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php new file mode 100644 index 000000000..6968c4ef8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php @@ -0,0 +1,668 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class TypedConstantsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that a ? after a "const" which is not the constant keyword is tokenized as ternary then, not as the nullable operator. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryIsInlineThen() + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken('/* testTernaryIsTernaryAfterConst */', [T_NULLABLE, T_INLINE_THEN]); + + $this->assertSame( + T_INLINE_THEN, + $tokens[$target]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$target]['code']).', not T_INLINE_THEN (code)' + ); + $this->assertSame( + 'T_INLINE_THEN', + $tokens[$target]['type'], + 'Token tokenized as '.$tokens[$target]['type'].', not T_INLINE_THEN (type)' + ); + + }//end testTernaryIsInlineThen() + + + /** + * Test the token name for an untyped constant is tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataUntypedConstant + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testUntypedConstant($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, T_CONST); + + for ($i = ($target + 1); $tokens[$i]['code'] !== T_EQUAL; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those. + continue; + } + + $this->assertSame( + T_STRING, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not T_STRING (code)' + ); + $this->assertSame( + 'T_STRING', + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_STRING (type)' + ); + } + + }//end testUntypedConstant() + + + /** + * Data provider. + * + * @see testUntypedConstant() + * + * @return array> + */ + public static function dataUntypedConstant() + { + return [ + 'non OO constant (untyped)' => [ + 'testMarker' => '/* testGlobalConstantCannotBeTyped */', + ], + 'OO constant, final, untyped' => [ + 'testMarker' => '/* testClassConstFinalUntyped */', + ], + 'OO constant, public, untyped, with comment' => [ + 'testMarker' => '/* testClassConstVisibilityUntyped */', + ], + ]; + + }//end dataUntypedConstant() + + + /** + * Test the tokens in the type of a typed constant as well as the constant name are tokenized correctly. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $sequence The expected token sequence. + * + * @dataProvider dataTypedConstant + * @dataProvider dataNullableTypedConstant + * @dataProvider dataUnionTypedConstant + * @dataProvider dataIntersectionTypedConstant + * @dataProvider dataDNFTypedConstant + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testTypedConstant($testMarker, array $sequence) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, T_CONST); + + $current = 0; + for ($i = ($target + 1); $tokens[$i]['code'] !== T_EQUAL; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those. + continue; + } + + $this->assertSame( + $sequence[$current], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.Tokens::tokenName($sequence[$current]).' (code)' + ); + + ++$current; + } + + }//end testTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataTypedConstant() + { + $data = [ + 'simple type: true' => [ + 'testMarker' => '/* testClassConstTypedTrue */', + 'sequence' => [T_TRUE], + ], + 'simple type: false' => [ + 'testMarker' => '/* testClassConstTypedFalse */', + 'sequence' => [T_FALSE], + ], + 'simple type: null' => [ + 'testMarker' => '/* testClassConstTypedNull */', + 'sequence' => [T_NULL], + ], + 'simple type: bool' => [ + 'testMarker' => '/* testClassConstTypedBool */', + 'sequence' => [T_STRING], + ], + 'simple type: int' => [ + 'testMarker' => '/* testClassConstTypedInt */', + 'sequence' => [T_STRING], + ], + 'simple type: float' => [ + 'testMarker' => '/* testClassConstTypedFloat */', + 'sequence' => [T_STRING], + ], + 'simple type: string' => [ + 'testMarker' => '/* testClassConstTypedString */', + 'sequence' => [T_STRING], + ], + 'simple type: array' => [ + 'testMarker' => '/* testClassConstTypedArray */', + 'sequence' => [T_STRING], + ], + 'simple type: object' => [ + 'testMarker' => '/* testClassConstTypedObject */', + 'sequence' => [T_STRING], + ], + 'simple type: iterable' => [ + 'testMarker' => '/* testClassConstTypedIterable */', + 'sequence' => [T_STRING], + ], + 'simple type: mixed' => [ + 'testMarker' => '/* testClassConstTypedMixed */', + 'sequence' => [T_STRING], + ], + 'simple type: unqualified name' => [ + 'testMarker' => '/* testClassConstTypedClassUnqualified */', + 'sequence' => [T_STRING], + ], + 'simple type: fully qualified name' => [ + 'testMarker' => '/* testClassConstTypedClassFullyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: namespace relative name' => [ + 'testMarker' => '/* testClassConstTypedClassNamespaceRelative */', + 'sequence' => [ + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: partially qualified name' => [ + 'testMarker' => '/* testClassConstTypedClassPartiallyQualified */', + 'sequence' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: parent' => [ + 'testMarker' => '/* testClassConstTypedParent */', + 'sequence' => [T_PARENT], + ], + + 'simple type: callable (invalid)' => [ + 'testMarker' => '/* testClassConstTypedCallable */', + 'sequence' => [T_CALLABLE], + ], + 'simple type: void (invalid)' => [ + 'testMarker' => '/* testClassConstTypedVoid */', + 'sequence' => [T_STRING], + ], + 'simple type: NEVER (invalid)' => [ + 'testMarker' => '/* testClassConstTypedNever */', + 'sequence' => [T_STRING], + ], + + 'simple type: self (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedSelf */', + 'sequence' => [T_SELF], + ], + 'simple type: static (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedStatic */', + 'sequence' => [T_STATIC], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataNullableTypedConstant() + { + $data = [ + // Global constants cannot be typed in PHP, but that's not our concern. + 'global typed constant, invalid, ?int' => [ + 'testMarker' => '/* testGlobalConstantTypedShouldStillBeHandled */', + 'sequence' => [T_STRING], + ], + + // OO constants. + 'nullable type: true' => [ + 'testMarker' => '/* testTraitConstTypedNullableTrue */', + 'sequence' => [T_TRUE], + ], + 'nullable type: false' => [ + 'testMarker' => '/* testTraitConstTypedNullableFalse */', + 'sequence' => [T_FALSE], + ], + 'nullable type: null' => [ + 'testMarker' => '/* testTraitConstTypedNullableNull */', + 'sequence' => [T_NULL], + ], + 'nullable type: bool' => [ + 'testMarker' => '/* testTraitConstTypedNullableBool */', + 'sequence' => [T_STRING], + ], + 'nullable type: int' => [ + 'testMarker' => '/* testTraitConstTypedNullableInt */', + 'sequence' => [T_STRING], + ], + 'nullable type: float' => [ + 'testMarker' => '/* testTraitConstTypedNullableFloat */', + 'sequence' => [T_STRING], + ], + 'nullable type: string' => [ + 'testMarker' => '/* testTraitConstTypedNullableString */', + 'sequence' => [T_STRING], + ], + 'nullable type: array' => [ + 'testMarker' => '/* testTraitConstTypedNullableArray */', + 'sequence' => [T_STRING], + ], + 'nullable type: object' => [ + 'testMarker' => '/* testTraitConstTypedNullableObject */', + 'sequence' => [T_STRING], + ], + 'nullable type: iterable' => [ + 'testMarker' => '/* testTraitConstTypedNullableIterable */', + 'sequence' => [T_STRING], + ], + 'nullable type: mixed' => [ + 'testMarker' => '/* testTraitConstTypedNullableMixed */', + 'sequence' => [T_STRING], + ], + 'nullable type: unqualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassUnqualified */', + 'sequence' => [T_STRING], + ], + 'nullable type: fully qualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassFullyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: namespace relative name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassNamespaceRelative */', + 'sequence' => [ + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: partially qualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassPartiallyQualified */', + 'sequence' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: parent' => [ + 'testMarker' => '/* testTraitConstTypedNullableParent */', + 'sequence' => [T_PARENT], + ], + + 'nullable type: self (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedNullableSelf */', + 'sequence' => [T_SELF], + ], + 'nullable type: static (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedNullableStatic */', + 'sequence' => [T_STATIC], + ], + ]; + + // The nullable operator, as the first token in the sequence, is always T_NULLABLE. + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + array_unshift($data[$key]['sequence'], T_NULLABLE); + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataNullableTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataUnionTypedConstant() + { + $data = [ + 'union type: true|null' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionTrueNull */', + 'sequence' => [ + T_TRUE, + T_TYPE_UNION, + T_NULL, + ], + ], + 'union type: array|object' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionArrayObject */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: string|array|int' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionStringArrayInt */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: float|bool|array' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionFloatBoolArray */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: iterable|false' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionIterableFalse */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_FALSE, + ], + ], + 'union type: Unqualified|Namespace\Relative' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionUnqualifiedNamespaceRelative */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'union type: FQN|Partial' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionFullyQualifiedPartiallyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_UNION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataUnionTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataIntersectionTypedConstant() + { + $data = [ + 'intersection type: Unqualified&Namespace\Relative' => [ + 'testMarker' => '/* testEnumConstTypedIntersectUnqualifiedNamespaceRelative */', + 'sequence' => [ + T_STRING, + T_TYPE_INTERSECTION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'intersection type: FQN&Partial' => [ + 'testMarker' => '/* testEnumConstTypedIntersectFullyQualifiedPartiallyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataIntersectionTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataDNFTypedConstant() + { + $data = [ + 'DNF type: null after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeNullAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_NULL, + ], + ], + 'DNF type: null before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeNullBefore */', + 'sequence' => [ + T_NULL, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: false before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeFalseBefore */', + 'sequence' => [ + T_FALSE, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: true after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeTrueAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_TRUE, + ], + ], + 'DNF type: true before, false after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeTrueBeforeFalseAfter */', + 'sequence' => [ + T_TRUE, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_FALSE, + ], + ], + 'DNF type: array after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeArrayAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + ], + ], + 'DNF type: array before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeArrayBefore */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: invalid nullable DNF' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeInvalidNullable */', + 'sequence' => [ + T_NULLABLE, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + ], + ], + 'DNF type: FQN/namespace relative/partially qualified names' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeFQNRelativePartiallyQualified */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_INTERSECTION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'DNF type: invalid self/parent/static' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeParentSelfStatic */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_PARENT, + T_TYPE_INTERSECTION, + T_SELF, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STATIC, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataDNFTypedConstant() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc index 540f72c9d..65c551a84 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc @@ -79,7 +79,7 @@ class MyClass /* testFunctionCallUnqualified */ echo function_name(); - /* testFunctionPartiallyQualified */ + /* testFunctionCallPartiallyQualified */ echo Level\function_name(); /* testCatchRelative */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.php similarity index 77% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.php index 24667e486..18a88fe8e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.php @@ -14,22 +14,23 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; -class UndoNamespacedNameSingleTokenTest extends AbstractMethodUnitTest +final class UndoNamespacedNameSingleTokenTest extends AbstractTokenizerTestCase { /** * Test that identifier names are tokenized the same across PHP versions, based on the PHP 5/7 tokenization. * - * @param string $testMarker The comment prefacing the test. - * @param array $expectedTokens The tokenization expected. + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. * * @dataProvider dataIdentifierTokenization * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -38,12 +39,20 @@ class UndoNamespacedNameSingleTokenTest extends AbstractMethodUnitTest */ public function testIdentifierTokenization($testMarker, $expectedTokens) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $identifier = $this->getTargetToken($testMarker, constant($expectedTokens[0]['type'])); - foreach ($expectedTokens as $key => $tokenInfo) { - $this->assertSame(constant($tokenInfo['type']), $tokens[$identifier]['code']); - $this->assertSame($tokenInfo['type'], $tokens[$identifier]['type']); + foreach ($expectedTokens as $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$identifier]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$identifier]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$identifier]['type'], + 'Token tokenized as '.$tokens[$identifier]['type'].', not '.$tokenInfo['type'].' (type)' + ); $this->assertSame($tokenInfo['content'], $tokens[$identifier]['content']); ++$identifier; @@ -57,14 +66,14 @@ public function testIdentifierTokenization($testMarker, $expectedTokens) * * @see testIdentifierTokenization() * - * @return array + * @return array>>> */ - public function dataIdentifierTokenization() + public static function dataIdentifierTokenization() { return [ - [ - '/* testNamespaceDeclaration */', - [ + 'namespace declaration' => [ + 'testMarker' => '/* testNamespaceDeclaration */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Package', @@ -75,9 +84,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNamespaceDeclarationWithLevels */', - [ + 'namespace declaration, multi-level' => [ + 'testMarker' => '/* testNamespaceDeclarationWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Vendor', @@ -104,9 +113,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testUseStatement */', - [ + 'import use statement, class' => [ + 'testMarker' => '/* testUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -117,9 +126,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testUseStatementWithLevels */', - [ + 'import use statement, class, multi-level' => [ + 'testMarker' => '/* testUseStatementWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Vendor', @@ -146,9 +155,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionUseStatement */', - [ + 'import use statement, function' => [ + 'testMarker' => '/* testFunctionUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function', @@ -167,9 +176,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionUseStatementWithLevels */', - [ + 'import use statement, function, multi-level' => [ + 'testMarker' => '/* testFunctionUseStatementWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function', @@ -204,9 +213,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testConstantUseStatement */', - [ + 'import use statement, constant' => [ + 'testMarker' => '/* testConstantUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'const', @@ -225,9 +234,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testConstantUseStatementWithLevels */', - [ + 'import use statement, constant, multi-level' => [ + 'testMarker' => '/* testConstantUseStatementWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'const', @@ -262,9 +271,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testMultiUseUnqualified */', - [ + 'import use statement, multi-statement, unqualified class' => [ + 'testMarker' => '/* testMultiUseUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'UnqualifiedClassName', @@ -275,9 +284,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testMultiUsePartiallyQualified */', - [ + 'import use statement, multi-statement, partially qualified class' => [ + 'testMarker' => '/* testMultiUsePartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Sublevel', @@ -296,9 +305,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testGroupUseStatement */', - [ + 'group use statement, multi-level prefix, mix inside group' => [ + 'testMarker' => '/* testGroupUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Vendor', @@ -492,9 +501,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testClassName */', - [ + 'class declaration' => [ + 'testMarker' => '/* testClassName */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'MyClass', @@ -506,9 +515,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testExtendedFQN */', - [ + 'class declaration, extends fully qualified name' => [ + 'testMarker' => '/* testExtendedFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -540,9 +549,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsRelative */', - [ + 'class declaration, implements namespace relative name' => [ + 'testMarker' => '/* testImplementsRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -561,9 +570,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsFQN */', - [ + 'class declaration, implements fully qualified name' => [ + 'testMarker' => '/* testImplementsFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -586,9 +595,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsUnqualified */', - [ + 'class declaration, implements unqualified name' => [ + 'testMarker' => '/* testImplementsUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Unqualified', @@ -599,9 +608,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsPartiallyQualified */', - [ + 'class declaration, implements partially qualified name' => [ + 'testMarker' => '/* testImplementsPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Sub', @@ -629,9 +638,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionName */', - [ + 'method declaration' => [ + 'testMarker' => '/* testFunctionName */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function_name', @@ -642,9 +651,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationRelative */', - [ + 'param type declaration, namespace relative name' => [ + 'testMarker' => '/* testTypeDeclarationRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -667,9 +676,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationFQN */', - [ + 'param type declaration, fully qualified name' => [ + 'testMarker' => '/* testTypeDeclarationFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -700,9 +709,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationUnqualified */', - [ + 'param type declaration, unqualified name' => [ + 'testMarker' => '/* testTypeDeclarationUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Unqualified', @@ -717,9 +726,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationPartiallyQualified */', - [ + 'param type declaration, partially qualified name' => [ + 'testMarker' => '/* testTypeDeclarationPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_NULLABLE', 'content' => '?', @@ -742,9 +751,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testReturnTypeFQN */', - [ + 'return type declaration, fully qualified name' => [ + 'testMarker' => '/* testReturnTypeFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NULLABLE', 'content' => '?', @@ -763,9 +772,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionCallRelative */', - [ + 'function call, namespace relative name' => [ + 'testMarker' => '/* testFunctionCallRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'NameSpace', @@ -784,9 +793,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionCallFQN */', - [ + 'function call, fully qualified name' => [ + 'testMarker' => '/* testFunctionCallFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -817,9 +826,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionCallUnqualified */', - [ + 'function call, unqualified name' => [ + 'testMarker' => '/* testFunctionCallUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function_name', @@ -830,9 +839,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionPartiallyQualified */', - [ + 'function call, partially qualified name' => [ + 'testMarker' => '/* testFunctionCallPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -851,9 +860,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchRelative */', - [ + 'catch, namespace relative name' => [ + 'testMarker' => '/* testCatchRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -880,9 +889,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchFQN */', - [ + 'catch, fully qualified name' => [ + 'testMarker' => '/* testCatchFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -897,9 +906,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchUnqualified */', - [ + 'catch, unqualified name' => [ + 'testMarker' => '/* testCatchUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Exception', @@ -910,9 +919,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchPartiallyQualified */', - [ + 'catch, partially qualified name' => [ + 'testMarker' => '/* testCatchPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -931,9 +940,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewRelative */', - [ + 'class instantiation, namespace relative name' => [ + 'testMarker' => '/* testNewRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -952,9 +961,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewFQN */', - [ + 'class instantiation, fully qualified name' => [ + 'testMarker' => '/* testNewFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -977,9 +986,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewUnqualified */', - [ + 'class instantiation, unqualified name' => [ + 'testMarker' => '/* testNewUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -990,9 +999,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewPartiallyQualified */', - [ + 'class instantiation, partially qualified name' => [ + 'testMarker' => '/* testNewPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -1011,9 +1020,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonRelative */', - [ + 'double colon class access, namespace relative name' => [ + 'testMarker' => '/* testDoubleColonRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -1032,9 +1041,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonFQN */', - [ + 'double colon class access, fully qualified name' => [ + 'testMarker' => '/* testDoubleColonFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -1049,9 +1058,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonUnqualified */', - [ + 'double colon class access, unqualified name' => [ + 'testMarker' => '/* testDoubleColonUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -1062,9 +1071,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonPartiallyQualified */', - [ + 'double colon class access, partially qualified name' => [ + 'testMarker' => '/* testDoubleColonPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -1083,9 +1092,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfRelative */', - [ + 'instanceof, namespace relative name' => [ + 'testMarker' => '/* testInstanceOfRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -1104,9 +1113,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfFQN */', - [ + 'instanceof, fully qualified name' => [ + 'testMarker' => '/* testInstanceOfFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -1129,9 +1138,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfUnqualified */', - [ + 'instanceof, unqualified name' => [ + 'testMarker' => '/* testInstanceOfUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -1142,9 +1151,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfPartiallyQualified */', - [ + 'instanceof, partially qualified name' => [ + 'testMarker' => '/* testInstanceOfPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Partially', @@ -1163,9 +1172,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInvalidInPHP8Whitespace */', - [ + 'function call, namespace relative, with whitespace (invalid in PHP 8)' => [ + 'testMarker' => '/* testInvalidInPHP8Whitespace */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -1213,9 +1222,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInvalidInPHP8Comments */', - [ + 'double colon class access, fully qualified, with whitespace and comments (invalid in PHP 8)' => [ + 'testMarker' => '/* testInvalidInPHP8Comments */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc new file mode 100644 index 000000000..3130b8460 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc @@ -0,0 +1,77 @@ +yield; + + /* testYieldUsedAsPropertyName2 */ + echo $obj?->yield(); + + /* testYieldUsedForClassConstantAccess1 */ + echo MyClass::YIELD; + /* testFromUsedForClassConstantAccess1 */ + echo MyClass::FROM; + } + + /* testYieldUsedAsMethodNameReturnByRef */ + public function &yield() {} +} + +function myGen() { + /* testYieldLiveCoding */ + yield diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php new file mode 100644 index 000000000..efb12096c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php @@ -0,0 +1,448 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests the tokenization of the `yield` and `yield from` keywords. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class YieldTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the yield keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent Expected token content. + * + * @dataProvider dataYieldKeyword + * + * @return void + */ + public function testYieldKeyword($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_YIELD, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD (code)'); + + // This assertion would fail on PHP 5.4 with PHPUnit 4 as PHPUnit polyfills the `T_YIELD` token too, but + // with a different value, which causes the token 'type' to be set to `UNKNOWN`. + // This issue _only_ occurs when running the tests, not when running PHPCS outside of a test situation. + // The PHPUnit polyfilled token is declared in the PHP_CodeCoverage_Report_HTML_Renderer_File class + // in vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/File.php. + if (PHP_VERSION_ID >= 50500) { + $this->assertSame('T_YIELD', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD (type)'); + } + + $this->assertSame($expectedContent, $tokenArray['content'], 'Token content does not match expectation'); + + }//end testYieldKeyword() + + + /** + * Data provider. + * + * @see testYieldKeyword() + * + * @return array> + */ + public static function dataYieldKeyword() + { + return [ + 'yield' => [ + 'testMarker' => '/* testYield */', + 'expectedContent' => 'yield', + ], + 'yield followed by comment' => [ + 'testMarker' => '/* testYieldFollowedByComment */', + 'expectedContent' => 'YIELD', + ], + 'yield at end of file, live coding' => [ + 'testMarker' => '/* testYieldLiveCoding */', + 'expectedContent' => 'yield', + ], + ]; + + }//end dataYieldKeyword() + + + /** + * Test that the yield from keyword is tokenized as a single token when it in on a single line + * and only has whitespace between the words. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent Expected token content. + * + * @dataProvider dataYieldFromKeywordSingleToken + * + * @return void + */ + public function testYieldFromKeywordSingleToken($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_YIELD_FROM, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD_FROM (code)'); + $this->assertSame('T_YIELD_FROM', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD_FROM (type)'); + + if (isset($tokenArray['orig_content']) === true) { + $this->assertSame($expectedContent, $tokenArray['orig_content'], 'Token (orig) content does not match expectation'); + } else { + $this->assertSame($expectedContent, $tokenArray['content'], 'Token content does not match expectation'); + } + + }//end testYieldFromKeywordSingleToken() + + + /** + * Data provider. + * + * @see testYieldFromKeywordSingleToken() + * + * @return array> + */ + public static function dataYieldFromKeywordSingleToken() + { + return [ + 'yield from' => [ + 'testMarker' => '/* testYieldFrom */', + 'expectedContent' => 'yield from', + ], + 'yield from with extra space between' => [ + 'testMarker' => '/* testYieldFromWithExtraSpacesBetween */', + 'expectedContent' => 'Yield From', + ], + 'yield from with tab between' => [ + 'testMarker' => '/* testYieldFromWithTabBetween */', + 'expectedContent' => 'yield from', + ], + ]; + + }//end dataYieldFromKeywordSingleToken() + + + /** + * Test that the yield from keyword is tokenized as a single token when it in on a single line + * and only has whitespace between the words. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokens The tokenization expected. + * + * @dataProvider dataYieldFromKeywordMultiToken + * + * @return void + */ + public function testYieldFromKeywordMultiToken($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + + foreach ($expectedTokens as $nr => $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$target]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$target]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$target]['type'], + 'Token tokenized as '.$tokens[$target]['type'].', not '.$tokenInfo['type'].' (type)' + ); + $this->assertSame( + $tokenInfo['content'], + $tokens[$target]['content'], + 'Content of token '.($nr + 1).' ('.$tokens[$target]['type'].') does not match expectations' + ); + + ++$target; + } + + }//end testYieldFromKeywordMultiToken() + + + /** + * Data provider. + * + * @see testYieldFromKeywordMultiToken() + * + * @return array>>> + */ + public static function dataYieldFromKeywordMultiToken() + { + return [ + 'yield from with new line' => [ + 'testMarker' => '/* testYieldFromSplitByNewLines */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'FROM', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'yield from with comment' => [ + 'testMarker' => '/* testYieldFromSplitByComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '/* comment */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with trailing comment' => [ + 'testMarker' => '/* testYieldFromWithTrailingComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with trailing annotation' => [ + 'testMarker' => '/* testYieldFromWithTrailingAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- for reasons. +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with new line and comment' => [ + 'testMarker' => '/* testYieldFromSplitByNewLineAndComments */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '/* comment line 1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' line 2 */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// another comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'yield from with new line and annotation' => [ + 'testMarker' => '/* testYieldFromSplitByNewLineAndAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'YIELD', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_DISABLE', + 'content' => '// @phpcs:disable Stnd.Cat.Sniff -- for reasons. +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'From', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + ]; + + }//end dataYieldFromKeywordMultiToken() + + + /** + * Test that 'yield' or 'from' when not used as the reserved keyword are tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataYieldNonKeyword + * + * @return void + */ + public function testYieldNonKeyword($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testYieldNonKeyword() + + + /** + * Data provider. + * + * @see testYieldNonKeyword() + * + * @return array> + */ + public static function dataYieldNonKeyword() + { + return [ + 'yield used as class name' => ['/* testYieldUsedAsClassName */'], + 'yield used as class constant name' => ['/* testYieldUsedAsClassConstantName */'], + 'yield used as method name' => ['/* testYieldUsedAsMethodName */'], + 'yield used as property access 1' => ['/* testYieldUsedAsPropertyName1 */'], + 'yield used as property access 2' => ['/* testYieldUsedAsPropertyName2 */'], + 'yield used as class constant access' => ['/* testYieldUsedForClassConstantAccess1 */'], + 'from used as class constant access' => ['/* testFromUsedForClassConstantAccess1 */'], + 'yield used as method name with ref' => ['/* testYieldUsedAsMethodNameReturnByRef */'], + ]; + + }//end dataYieldNonKeyword() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc new file mode 100644 index 000000000..89031bd19 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc @@ -0,0 +1,185 @@ + 10 ) {} + +/* testParensOwnerFor */ +for ($i =0; $i < /* testParensNoOwnerInForCondition */ ( CONST_A & CONST_B ); $i++ ); + +/* testParensOwnerMatch */ +$match = match(CONST_A & CONST_B) { + default => $a, +}; + +/* testParensOwnerArray */ +$array = array ( + 'text', + \CONST_A & \Fully\Qualified\CONST_B, + /* testParensNoOwnerFunctionCallWithAmpersandInCallable */ + do_something($a, /* testParensOwnerArrowFn */ fn($b) => $a & $b, $c), +); + +/* testParensOwnerListWithRefVars */ +list(&$a, &$b) = $array; + +/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + + +/* + * DNF parentheses. + */ + +abstract class DNFTypes { + /* testDNFTypeOOConstUnqualifiedClasses */ + public const (A&B)|D UNQUALIFIED = new Foo; + + /* testDNFTypeOOConstReverseModifierOrder */ + protected final const int|(Foo&Bar)|float MODIFIERS_REVERSED /* testParensNoOwnerOOConstDefaultValue */ = (E_WARNING & E_NOTICE) | E_DEPRECATED; + + const + /* testDNFTypeOOConstMulti1 */ + (A&B) | + /* testDNFTypeOOConstMulti2 */ + (C&D) | // phpcs:ignore Stnd.Cat.Sniff + /* testDNFTypeOOConstMulti3 */ + (Y&D) + | null MULTI_DNF = null; + + /* testDNFTypeOOConstNamespaceRelative */ + final protected const (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testDNFTypeOOConstPartiallyQualified */ + const Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testDNFTypeOOConstFullyQualified */ + const (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameC FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + + /* testDNFTypePropertyUnqualifiedClasses */ + public static (Foo&Bar)|array $obj; + + /* testDNFTypePropertyReverseModifierOrder */ + static protected string|(A&B)|int $dnf /* testParensNoOwnerPropertyDefaultValue1 */ = ( E_WARNING & E_NOTICE ) | /* testParensNoOwnerPropertyDefaultValue2 */ (E_ALL & E_DEPRECATED); + + private + /* testDNFTypePropertyMultiNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB) | + /* testDNFTypePropertyMultiPartiallyQualified */ + (Partially\Qualified\NameA&Partially\Qualified\NameB) | // phpcs:ignore Stnd.Cat.Sniff + false + /* testDNFTypePropertyMultiFullyQualified */ + | (\Fully\Qualified\NameA&\Fully\Qualified\NameB) $multiDnf; + + /* testDNFTypePropertyWithReadOnlyKeyword1 */ + protected readonly (A&B) | /* testDNFTypePropertyWithReadOnlyKeyword2 */ (C&D) $readonly; + + /* testDNFTypePropertyWithStaticAndReadOnlyKeywords */ + static readonly (A&B&C)|array $staticReadonly; + + /* testDNFTypePropertyWithOnlyStaticKeyword */ + static (A&B&C)|true $onlyStaticModified; + + public function paramTypes( + /* testDNFTypeParam1WithAttribute */ + #[MyAttribute] + (\Foo&Bar)|int|float $paramA /* testParensNoOwnerParamDefaultValue */ = SOMETHING | (CONSTANT_A & CONSTANT_B), + + /* testDNFTypeParam2 */ + (Foo&\Bar) /* testDNFTypeParam3 */ |(Baz&Fop) &...$paramB, + ) { + /* testParensNoOwnerInReturnValue1 */ + return ( + /* testParensNoOwnerInReturnValue2 */ + ($a1 & $b1) | + /* testParensNoOwnerInReturnValue3 */ + ($a2 & $b2) + ) + $c; + } + + public function identifierNames( + /* testDNFTypeParamNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB)|false $paramA, + /* testDNFTypeParamPartiallyQualified */ + Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) $paramB, + /* testDNFTypeParamFullyQualified */ + name|(\Fully\Qualified\NameA&\Fully\Qualified\NameB) $paramC, + ) {} + + public function __construct( + /* testDNFTypeConstructorPropertyPromotion1 */ + public (A&B)| /* testDNFTypeConstructorPropertyPromotion2 */ (A&D) $property + ) {} + + public function returnType()/* testDNFTypeReturnType1 */ : A|(B&D)|/* testDNFTypeReturnType2 */(B&W)|null {} + + abstract public function abstractMethod(): /* testDNFTypeAbstractMethodReturnType1 */ (X&Y) /* testDNFTypeAbstractMethodReturnType2 */ |(W&Z); + + public function identifierNamesReturnRelative( + ) : /* testDNFTypeReturnTypeNamespaceRelative */ (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC {} + + public function identifierNamesReturnPQ( + ) : /* testDNFTypeReturnPartiallyQualified */Partially\Qualified\NameA|(Partially\Qualified\NameB&Partially\Qualified\NameC) {} + + // Illegal type: segments which are strict subsets of others are disallowed, but that's not the concern of the tokenizer. + public function identifierNamesReturnFQ( + ) /* testDNFTypeReturnFullyQualified */ : (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameB {} +} + +function globalFunctionWithSpreadAndReference( + /* testDNFTypeWithReference */ + float|(B&A) &$paramA, + /* testDNFTypeWithSpreadOperator */ + string|(B&D) ...$paramB +) {} + + +$closureWithParamType = function ( /* testDNFTypeClosureParamIllegalNullable */ ?(A&B)|bool $string) {}; + +/* testParensOwnerClosureAmpersandInDefaultValue */ +$closureWithReturnType = function ($string = NONSENSE & FAKE) /* testDNFTypeClosureReturn */ : (\Package\MyA&PackageB)|null {}; + +/* testParensOwnerArrowDNFUsedWithin */ +$arrowWithParamType = fn ( + /* testDNFTypeArrowParam */ + int|(A&B&C)|array $param, + /* testParensNoOwnerAmpersandInDefaultValue */ ?int $int = (CONSTA & CONSTB )| CONST_C +) + /* testParensNoOwnerInArrowReturnExpression */ + => ($param & $foo ) | $int; + +$arrowWithReturnType = fn ($param) : /* testDNFTypeArrowReturnType */ int|(A&B) => $param * 10; + +$arrowWithParamReturnByRef = fn &( + /* testDNFTypeArrowParamWithReturnByRef */ + (A&B)|null $param +) => $param * 10; + +function InvalidSyntaxes( + /* testDNFTypeParamIllegalUnnecessaryParens */ + (A&B) $parensNotNeeded, + + /* testDNFTypeParamIllegalIntersectUnionReversed */ + A&(B|D) $onlyIntersectAllowedWithinParensAndUnionOutside, + + /* testDNFTypeParamIllegalNestedParens */ + A|(B&(D|W)|null) $nestedParensNotAllowed, +) {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php new file mode 100644 index 000000000..6a82af669 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php @@ -0,0 +1,374 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class CreateParenthesisNestingMapDNFTypesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that parentheses when **not** used in a type declaration are correctly tokenized. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|false $owner Optional. The parentheses owner or false when no parentheses owner is expected. + * + * @dataProvider dataNormalParentheses + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createParenthesisNestingMap + * + * @return void + */ + public function testNormalParentheses($testMarker, $owner=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (code)'); + + if ($owner !== false) { + $this->assertArrayHasKey('parenthesis_owner', $opener, 'Parenthesis owner is not set'); + $this->assertSame(($openPtr + $owner), $opener['parenthesis_owner'], 'Opener parenthesis owner is not the expected token'); + } else { + $this->assertArrayNotHasKey('parenthesis_owner', $opener, 'Parenthesis owner is set'); + } + + $this->assertArrayHasKey('parenthesis_opener', $opener, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $opener, 'Parenthesis closer is not set'); + $this->assertSame($openPtr, $opener['parenthesis_opener'], 'Parenthesis opener is not the expected token'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (code)'); + + if ($owner !== false) { + $this->assertArrayHasKey('parenthesis_owner', $closer, 'Parenthesis owner is not set'); + $this->assertSame(($openPtr + $owner), $closer['parenthesis_owner'], 'Closer parenthesis owner is not the expected token'); + } else { + $this->assertArrayNotHasKey('parenthesis_owner', $closer, 'Parenthesis owner is set'); + } + + $this->assertArrayHasKey('parenthesis_opener', $closer, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $closer, 'Parenthesis closer is not set'); + $this->assertSame($closePtr, $closer['parenthesis_closer'], 'Parenthesis closer is not the expected token'); + + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + $this->assertArrayHasKey('nested_parenthesis', $tokens[$i], "Nested parenthesis key not set on token $i ({$tokens[$i]['type']})"); + $this->assertArrayHasKey($openPtr, $tokens[$i]['nested_parenthesis'], 'Nested parenthesis is missing target parentheses set'); + $this->assertSame($closePtr, $tokens[$i]['nested_parenthesis'][$openPtr], 'Nested parenthesis closer not set correctly'); + } + + }//end testNormalParentheses() + + + /** + * Data provider. + * + * @see testNormalParentheses() + * + * @return array> + */ + public static function dataNormalParentheses() + { + // "Owner" offsets are relative to the open parenthesis. + return [ + 'parens without owner' => [ + 'testMarker' => '/* testParensNoOwner */', + ], + 'parens without owner in ternary then' => [ + 'testMarker' => '/* testParensNoOwnerInTernary */', + ], + 'parens without owner in short ternary' => [ + 'testMarker' => '/* testParensNoOwnerInShortTernary */', + ], + 'parens with owner: function; & in default value' => [ + 'testMarker' => '/* testParensOwnerFunctionAmpersandInDefaultValue */', + 'owner' => -3, + ], + 'parens with owner: closure; param declared by & ref' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandParamRef */', + 'owner' => -1, + ], + 'parens with owner: if' => [ + 'testMarker' => '/* testParensOwnerIf */', + 'owner' => -2, + ], + 'parens without owner in if condition' => [ + 'testMarker' => '/* testParensNoOwnerInIfCondition */', + ], + 'parens with owner: for' => [ + 'testMarker' => '/* testParensOwnerFor */', + 'owner' => -2, + ], + 'parens without owner in for condition' => [ + 'testMarker' => '/* testParensNoOwnerInForCondition */', + ], + 'parens with owner: match' => [ + 'testMarker' => '/* testParensOwnerMatch */', + 'owner' => -1, + ], + 'parens with owner: array' => [ + 'testMarker' => '/* testParensOwnerArray */', + 'owner' => -2, + ], + 'parens without owner in array; function call with & in callable' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithAmpersandInCallable */', + ], + 'parens with owner: fn; & in return value' => [ + 'testMarker' => '/* testParensOwnerArrowFn */', + 'owner' => -1, + ], + 'parens with owner: list with reference vars' => [ + 'testMarker' => '/* testParensOwnerListWithRefVars */', + 'owner' => -1, + ], + 'parens without owner, function call with DNF look-a-like param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */', + ], + + 'parens without owner in OO const default value' => [ + 'testMarker' => '/* testParensNoOwnerOOConstDefaultValue */', + ], + 'parens without owner in property default 1' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue1 */', + ], + 'parens without owner in property default 2' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue2 */', + ], + 'parens without owner in param default value' => [ + 'testMarker' => '/* testParensNoOwnerParamDefaultValue */', + ], + 'parens without owner in return statement 1' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue1 */', + ], + 'parens without owner in return statement 2' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue2 */', + ], + 'parens without owner in return statement 3' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue3 */', + ], + 'parens with owner: closure; & in default value' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandInDefaultValue */', + 'owner' => -2, + ], + 'parens with owner: fn; dnf used within' => [ + 'testMarker' => '/* testParensOwnerArrowDNFUsedWithin */', + 'owner' => -2, + ], + 'parens without owner: default value for param in arrow function' => [ + 'testMarker' => '/* testParensNoOwnerAmpersandInDefaultValue */', + ], + 'parens without owner in arrow function return expression' => [ + 'testMarker' => '/* testParensNoOwnerInArrowReturnExpression */', + ], + ]; + + }//end dataNormalParentheses() + + + /** + * Test that parentheses when used in a DNF type declaration are correctly tokenized. + * + * Includes verifying that: + * - the tokens between the parentheses all have a "nested_parenthesis" key. + * - all ampersands between the parentheses are tokenized as T_TYPE_INTERSECTION. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataDNFTypeParentheses + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createParenthesisNestingMap + * + * @return void + */ + public function testDNFTypeParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_TYPE_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $opener, 'Parenthesis owner is set'); + $this->assertArrayHasKey('parenthesis_opener', $opener, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $opener, 'Parenthesis closer is not set'); + $this->assertSame($openPtr, $opener['parenthesis_opener'], 'Parenthesis opener is not the expected token'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_TYPE_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $closer, 'Parenthesis owner is set'); + $this->assertArrayHasKey('parenthesis_opener', $closer, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $closer, 'Parenthesis closer is not set'); + $this->assertSame($closePtr, $closer['parenthesis_closer'], 'Parenthesis closer is not the expected token'); + + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + $this->assertArrayHasKey('nested_parenthesis', $tokens[$i], "Nested parenthesis key not set on token $i ({$tokens[$i]['type']})"); + $this->assertArrayHasKey($openPtr, $tokens[$i]['nested_parenthesis'], 'Nested parenthesis is missing target parentheses set'); + $this->assertSame($closePtr, $tokens[$i]['nested_parenthesis'][$openPtr], 'Nested parenthesis closer not set correctly'); + }//end for + + }//end testDNFTypeParentheses() + + + /** + * Data provider. + * + * @see testDNFTypeParentheses() + * + * @return array> + */ + public static function dataDNFTypeParentheses() + { + return [ + 'OO const type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstUnqualifiedClasses */', + ], + 'OO const type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypeOOConstReverseModifierOrder */', + ], + 'OO const type: multi-dnf part 1' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti1 */', + ], + 'OO const type: multi-dnf part 2' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti2 */', + ], + 'OO const type: multi-dnf part 3' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti3 */', + ], + 'OO const type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeOOConstNamespaceRelative */', + ], + 'OO const type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstPartiallyQualified */', + ], + 'OO const type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstFullyQualified */', + ], + + 'OO property type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyUnqualifiedClasses */', + ], + 'OO property type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypePropertyReverseModifierOrder */', + ], + 'OO property type: multi-dnf namespace relative classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiNamespaceRelative */', + ], + 'OO property type: multi-dnf partially qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiPartiallyQualified */', + ], + 'OO property type: multi-dnf fully qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiFullyQualified */', + ], + + 'OO property type: multi-dnf with readonly keyword 1' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword1 */', + ], + 'OO property type: multi-dnf with readonly keyword 2' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword2 */', + ], + 'OO property type: with static and readonly keywords' => [ + 'testMarker' => '/* testDNFTypePropertyWithStaticAndReadOnlyKeywords */', + ], + 'OO property type: with only static keyword' => [ + 'testMarker' => '/* testDNFTypePropertyWithOnlyStaticKeyword */', + ], + 'OO method param type: first param' => [ + 'testMarker' => '/* testDNFTypeParam1WithAttribute */', + ], + 'OO method param type: second param, first DNF' => [ + 'testMarker' => '/* testDNFTypeParam2 */', + ], + 'OO method param type: second param, second DNF' => [ + 'testMarker' => '/* testDNFTypeParam3 */', + ], + 'OO method param type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeParamNamespaceRelative */', + ], + 'OO method param type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamPartiallyQualified */', + ], + 'OO method param type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamFullyQualified */', + ], + 'Constructor property promotion with multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion1 */', + ], + 'Constructor property promotion with multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion2 */', + ], + 'OO method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeReturnType1 */', + ], + 'OO method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeReturnType2 */', + ], + 'OO abstract method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType1 */', + ], + 'OO abstract method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType2 */', + ], + 'OO method return type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeReturnTypeNamespaceRelative */', + ], + 'OO method return type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnPartiallyQualified */', + ], + 'OO method return type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnFullyQualified */', + ], + 'function param type: with reference' => [ + 'testMarker' => '/* testDNFTypeWithReference */', + ], + 'function param type: with spread' => [ + 'testMarker' => '/* testDNFTypeWithSpreadOperator */', + ], + 'closure param type: with illegal nullable' => [ + 'testMarker' => '/* testDNFTypeClosureParamIllegalNullable */', + ], + 'closure return type' => [ + 'testMarker' => '/* testDNFTypeClosureReturn */', + ], + 'arrow function param type' => [ + 'testMarker' => '/* testDNFTypeArrowParam */', + ], + 'arrow function return type' => [ + 'testMarker' => '/* testDNFTypeArrowReturnType */', + ], + 'arrow function param type with return by ref' => [ + 'testMarker' => '/* testDNFTypeArrowParamWithReturnByRef */', + ], + + 'illegal syntax: unnecessary parentheses (no union)' => [ + 'testMarker' => '/* testDNFTypeParamIllegalUnnecessaryParens */', + ], + 'illegal syntax: union within parentheses, intersect outside' => [ + 'testMarker' => '/* testDNFTypeParamIllegalIntersectUnionReversed */', + ], + 'illegal syntax: nested parentheses' => [ + 'testMarker' => '/* testDNFTypeParamIllegalNestedParens */', + ], + ]; + + }//end dataDNFTypeParentheses() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.php new file mode 100644 index 000000000..fb9f04939 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.php @@ -0,0 +1,117 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Heredoc/nowdoc closer token test. + * + * @requires PHP 7.3 + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapHeredocNowdocCloserTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that leading (indent) whitespace in a heredoc/nowdoc closer token get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * + * @dataProvider dataHeredocNowdocCloserTabReplacement + * + * @return void + */ + public function testHeredocNowdocCloserTabReplacement($testMarker, $expected) + { + $tokens = $this->phpcsFile->getTokens(); + + $closer = $this->getTargetToken($testMarker, [T_END_HEREDOC, T_END_NOWDOC]); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$closer], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$closer], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$closer][$key], "Value for key $key does not match expectation."); + } + + }//end testHeredocNowdocCloserTabReplacement() + + + /** + * Data provider. + * + * @see testHeredocNowdocCloserTabReplacement() + * + * @return array>> + */ + public static function dataHeredocNowdocCloserTabReplacement() + { + return [ + 'Heredoc closer without indent' => [ + 'testMarker' => '/* testHeredocCloserNoIndent */', + 'expected' => [ + 'length' => 3, + 'content' => 'EOD', + 'orig_content' => null, + ], + ], + 'Nowdoc closer without indent' => [ + 'testMarker' => '/* testNowdocCloserNoIndent */', + 'expected' => [ + 'length' => 3, + 'content' => 'EOD', + 'orig_content' => null, + ], + ], + 'Heredoc closer with indent, spaces' => [ + 'testMarker' => '/* testHeredocCloserSpaceIndent */', + 'expected' => [ + 'length' => 7, + 'content' => ' END', + 'orig_content' => null, + ], + ], + 'Nowdoc closer with indent, spaces' => [ + 'testMarker' => '/* testNowdocCloserSpaceIndent */', + 'expected' => [ + 'length' => 8, + 'content' => ' END', + 'orig_content' => null, + ], + ], + 'Heredoc closer with indent, tabs' => [ + 'testMarker' => '/* testHeredocCloserTabIndent */', + 'expected' => [ + 'length' => 8, + 'content' => ' END', + 'orig_content' => ' END', + ], + ], + 'Nowdoc closer with indent, tabs' => [ + 'testMarker' => '/* testNowdocCloserTabIndent */', + 'expected' => [ + 'length' => 7, + 'content' => ' END', + 'orig_content' => ' END', + ], + ], + ]; + + }//end dataHeredocNowdocCloserTabReplacement() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc new file mode 100644 index 000000000..dc2b2f2dc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc @@ -0,0 +1,31 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Heredoc/nowdoc opener token test. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapHeredocNowdocOpenerTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that spaces/tabs in a heredoc/nowdoc opener token get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * + * @dataProvider dataHeredocNowdocOpenerTabReplacement + * + * @return void + */ + public function testHeredocNowdocOpenerTabReplacement($testMarker, $expected) + { + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_START_HEREDOC, T_START_NOWDOC]); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$opener], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$opener], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$opener][$key], "Value for key $key does not match expectation."); + } + + }//end testHeredocNowdocOpenerTabReplacement() + + + /** + * Data provider. + * + * @see testHeredocNowdocOpenerTabReplacement() + * + * @return array>> + */ + public static function dataHeredocNowdocOpenerTabReplacement() + { + return [ + 'Heredoc opener without space' => [ + 'testMarker' => '/* testHeredocOpenerNoSpace */', + 'expected' => [ + 'length' => 6, + 'content' => '<< null, + ], + ], + 'Nowdoc opener without space' => [ + 'testMarker' => '/* testNowdocOpenerNoSpace */', + 'expected' => [ + 'length' => 8, + 'content' => "<<<'EOD' +", + 'orig_content' => null, + ], + ], + 'Heredoc opener with space(s)' => [ + 'testMarker' => '/* testHeredocOpenerHasSpace */', + 'expected' => [ + 'length' => 7, + 'content' => '<<< END +', + 'orig_content' => null, + ], + ], + 'Nowdoc opener with space(s)' => [ + 'testMarker' => '/* testNowdocOpenerHasSpace */', + 'expected' => [ + 'length' => 21, + 'content' => "<<< 'END' +", + 'orig_content' => null, + ], + ], + 'Heredoc opener with tab(s)' => [ + 'testMarker' => '/* testHeredocOpenerHasTab */', + 'expected' => [ + 'length' => 18, + 'content' => '<<< "END" +', + 'orig_content' => '<<< "END" +', + ], + ], + 'Nowdoc opener with tab(s)' => [ + 'testMarker' => '/* testNowdocOpenerHasTab */', + 'expected' => [ + 'length' => 11, + 'content' => "<<< 'END' +", + 'orig_content' => "<<< 'END' +", + ], + ], + ]; + + }//end dataHeredocNowdocOpenerTabReplacement() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php new file mode 100644 index 000000000..fd47bf7da --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php @@ -0,0 +1,107 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 0, means no tab replacement will take place. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapTabWidth0Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 0; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 2, + 'content' => ' ', + 'orig_content' => null, + ], + 'Mixed tab/space indentation' => [ + 'length' => 3, + 'content' => ' ', + 'orig_content' => null, + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => null, + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 24, + 'content' => '"tab $between each word"', + 'orig_content' => null, + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 15, + 'content' => 'tab separated +', + 'orig_content' => null, + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 27, + 'content' => 'tab between each word +', + 'orig_content' => null, + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 20, + 'content' => "'tab separated'", + 'orig_content' => null, + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 31, + 'content' => '"tab $between each word"', + 'orig_content' => null, + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => null, + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => null, + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => null, + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => null, + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc new file mode 100644 index 000000000..59365dd5c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc @@ -0,0 +1,15 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Yield from token test. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapYieldFromTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that spaces/tabs in "yield from" tokens get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * @param string $content Optional. The test token content to search for. + * Defaults to null. + * + * @dataProvider dataYieldFromTabReplacement + * + * @return void + */ + public function testYieldFromTabReplacement($testMarker, $expected, $content=null) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD_FROM], $content); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testYieldFromTabReplacement() + + + /** + * Data provider. + * + * @see testYieldFromTabReplacement() + * + * @return array>> + */ + public static function dataYieldFromTabReplacement() + { + return [ + 'Yield from, single line, single space' => [ + 'testMarker' => '/* testYieldFromHasSingleSpace */', + 'expected' => [ + 'length' => 10, + 'content' => 'yield from', + 'orig_content' => null, + ], + ], + 'Yield from, single line, multiple spaces' => [ + 'testMarker' => '/* testYieldFromHasMultiSpace */', + 'expected' => [ + 'length' => 14, + 'content' => 'yield from', + 'orig_content' => null, + ], + ], + 'Yield from, single line, has tabs' => [ + 'testMarker' => '/* testYieldFromHasTabs */', + 'expected' => [ + 'length' => 16, + 'content' => 'yield from', + 'orig_content' => 'yield from', + ], + ], + 'Yield from, single line, mix of tabs and spaces' => [ + 'testMarker' => '/* testYieldFromMixedTabsSpaces */', + 'expected' => [ + 'length' => 20, + 'content' => 'Yield From', + 'orig_content' => 'Yield From', + ], + ], + ]; + + }//end dataYieldFromTabReplacement() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc new file mode 100644 index 000000000..6d8adfcba --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc @@ -0,0 +1,58 @@ + 10); + +/* testArrayWithComment */ +$var = Array /*comment*/ (1 => 10); + +/* testNestingArray */ +$var = array( + /* testNestedArray */ + array( + 'key' => 'value', + + /* testClosureReturnType */ + 'closure' => function($a) use($global) : Array {}, + ), +); + +/* testFunctionDeclarationParamType */ +function typedParam(array $a) {} + +/* testFunctionDeclarationReturnType */ +function returnType($a) : int|array|null {} + +class Bar { + /* testClassConst */ + const ARRAY = []; + + /* testClassMethod */ + public function array() {} + + /* testOOConstType */ + const array /* testTypedOOConstName */ ARRAY = /* testOOConstDefault */ array(); + + /* testOOPropertyType */ + protected array $property; +} + +class DNFTypes { + /* testOOConstDNFType */ + const (A&B)|array|(C&D) NAME = []; + + /* testOOPropertyDNFType */ + protected (A&B)|ARRAY|null $property; + + /* testFunctionDeclarationParamDNFType */ + public function name(null|array|(A&B) $param) { + /* testClosureDeclarationParamDNFType */ + $cl = function ( array|(A&B) $param) {}; + + /* testArrowDeclarationReturnDNFType */ + $arrow = fn($a): (A&B)|Array => new $a; + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php new file mode 100644 index 000000000..4b7ac382a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php @@ -0,0 +1,212 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class CreateTokenMapArrayParenthesesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the array keyword is correctly tokenized as `T_ARRAY`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)'); + + $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); + + }//end testArrayKeyword() + + + /** + * Data provider. + * + * @see testArrayKeyword() + * + * @return array> + */ + public static function dataArrayKeyword() + { + return [ + 'empty array' => [ + 'testMarker' => '/* testEmptyArray */', + ], + 'array with space before parenthesis' => [ + 'testMarker' => '/* testArrayWithSpace */', + ], + 'array with comment before parenthesis' => [ + 'testMarker' => '/* testArrayWithComment */', + 'testContent' => 'Array', + ], + 'nested: outer array' => [ + 'testMarker' => '/* testNestingArray */', + ], + 'nested: inner array' => [ + 'testMarker' => '/* testNestedArray */', + ], + 'OO constant default value' => [ + 'testMarker' => '/* testOOConstDefault */', + ], + ]; + + }//end dataArrayKeyword() + + + /** + * Test that the array keyword when used in a type declaration is correctly tokenized as `T_STRING`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayType + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testArrayType($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testArrayType() + + + /** + * Data provider. + * + * @see testArrayType() + * + * @return array> + */ + public static function dataArrayType() + { + return [ + 'closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'testContent' => 'Array', + ], + 'function param type' => [ + 'testMarker' => '/* testFunctionDeclarationParamType */', + ], + 'function union return type' => [ + 'testMarker' => '/* testFunctionDeclarationReturnType */', + ], + 'OO constant type' => [ + 'testMarker' => '/* testOOConstType */', + ], + 'OO property type' => [ + 'testMarker' => '/* testOOPropertyType */', + ], + + 'OO constant DNF type' => [ + 'testMarker' => '/* testOOConstDNFType */', + ], + 'OO property DNF type' => [ + 'testMarker' => '/* testOOPropertyDNFType */', + 'testContent' => 'ARRAY', + ], + 'function param DNF type' => [ + 'testMarker' => '/* testFunctionDeclarationParamDNFType */', + ], + 'closure param DNF type' => [ + 'testMarker' => '/* testClosureDeclarationParamDNFType */', + ], + 'arrow return DNF type' => [ + 'testMarker' => '/* testArrowDeclarationReturnDNFType */', + 'testContent' => 'Array', + ], + ]; + + }//end dataArrayType() + + + /** + * Verify that the retokenization of `T_ARRAY` tokens to `T_STRING` is handled correctly + * for tokens with the contents 'array' which aren't in actual fact the array keyword. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testNotArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testNotArrayKeyword() + + + /** + * Data provider. + * + * @see testNotArrayKeyword() + * + * @return array> + */ + public static function dataNotArrayKeyword() + { + return [ + 'class-constant-name' => [ + 'testMarker' => '/* testClassConst */', + 'testContent' => 'ARRAY', + ], + 'class-method-name' => [ + 'testMarker' => '/* testClassMethod */', + ], + 'class-constant-name-after-type' => [ + 'testMarker' => '/* testTypedOOConstName */', + 'testContent' => 'ARRAY', + ], + ]; + + }//end dataNotArrayKeyword() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc new file mode 100644 index 000000000..8df21a6c3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc @@ -0,0 +1,132 @@ + $num) + return bar( + baz( + "foobarbaz" + ) + ); + break; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php new file mode 100644 index 000000000..51382d3c5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php @@ -0,0 +1,271 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapCaseKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that enum "case" tokens does not get scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataEnumCases + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testEnumCases($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$enumCase]; + + // Make sure we're looking at the right token. + $this->assertSame(T_ENUM_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (code)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testEnumCases() + + + /** + * Data provider. + * + * @see testEnumCases() + * + * @return array> + */ + public static function dataEnumCases() + { + return [ + 'enum case, no value' => ['/* testPureEnumCase */'], + 'enum case, integer value' => ['/* testBackingIntegerEnumCase */'], + 'enum case, string value' => ['/* testBackingStringEnumCase */'], + 'enum case, integer value in more complex enum' => ['/* testEnumCaseInComplexEnum */'], + 'enum case, keyword in mixed case' => ['/* testEnumCaseIsCaseInsensitive */'], + 'enum case, after switch statement' => ['/* testEnumCaseAfterSwitch */'], + 'enum case, after switch statement using alternative syntax' => ['/* testEnumCaseAfterSwitchWithEndSwitch */'], + ]; + + }//end dataEnumCases() + + + /** + * Test that switch "case" tokens do get the scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. + * + * @dataProvider dataNotEnumCases + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testNotEnumCases($testMarker, $expectedTokens, $testCloserMarker=null) + { + $tokens = $this->phpcsFile->getTokens(); + $caseIndex = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$caseIndex]; + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $caseIndex; + $expectedScopeOpener = $this->getTargetToken($testMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); + + // Make sure we're looking at the right token. + $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_CASE, found %s.', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s.', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s.', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testNotEnumCases() + + + /** + * Data provider. + * + * @see testNotEnumCases() + * + * @return array>> + */ + public static function dataNotEnumCases() + { + return [ + 'switch case with constant, semicolon condition end' => [ + 'testMarker' => '/* testCaseWithSemicolonIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + ], + 'switch case with constant, colon condition end' => [ + 'testMarker' => '/* testCaseWithConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, comparison' => [ + 'testMarker' => '/* testCaseWithConstantAndIdenticalIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, assignment' => [ + 'testMarker' => '/* testCaseWithAssigmentToConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, keyword in mixed case' => [ + 'testMarker' => '/* testIsNotEnumCaseIsCaseInsensitive */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case, body in curlies declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1 */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1CloserMarker */', + ], + 'switch case, body after semicolon declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2 */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_BREAK, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2CloserMarker */', + ], + 'switch case, shared closer with switch' => [ + 'testMarker' => '/* testSwitchCaseScopeCloserSharedWithSwitch */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + ], + 'switch case, nested inline if/elseif/else with and without braces' => [ + 'testMarker' => '/* testSwitchCaseNestedIfWithAndWithoutBraces */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], + 'switch case, nested inline if' => [ + 'testMarker' => '/* testSwitchCaseNestedInlineIfWithMoreThanThreeLines */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], + ]; + + }//end dataNotEnumCases() + + + /** + * Test that a "case" keyword which is not a switch or enum case, does not get the scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataKeywordAsEnumCaseNameShouldBeString + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testKeywordAsEnumCaseNameShouldBeString($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]); + $tokenArray = $tokens[$enumCaseName]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testKeywordAsEnumCaseNameShouldBeString() + + + /** + * Data provider. + * + * @see testKeywordAsEnumCaseNameShouldBeString() + * + * @return array> + */ + public static function dataKeywordAsEnumCaseNameShouldBeString() + { + return [ + '"interface" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], + '"trait" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], + '"enum" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], + '"function" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], + '"false" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString5 */'], + '"default" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString6 */'], + '"array" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString7 */'], + ]; + + }//end dataKeywordAsEnumCaseNameShouldBeString() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc new file mode 100644 index 000000000..c98f518cb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc @@ -0,0 +1,231 @@ + 1, + 2 => 2, + /* testSimpleMatchDefault */ + default => 'default', + }; +} + +function switchWithDefault($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefault */ + default: + return 'default'; + } +} + +function switchWithDefaultAndCurlies($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefaultWithCurlies */ + default: /* testSimpleSwitchDefaultWithCurliesScopeOpener */ { + /* testSimpleSwitchDefaultWithCurliesConditionStop */ + return 'default'; + /* testSimpleSwitchDefaultWithCurliesScopeCloser */ + } + } +} + +function matchWithDefaultInSwitch() { + switch ($something) { + case 'foo': + $var = [1, 2, 3]; + $var = match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase1 */ + default => 'default', + }; + continue; + + case 'bar' : + $i = callMe($a, $b); + return match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase2 */ + default => 'default', + }; + + /* testSwitchDefault */ + default; + echo 'something', match ($i) { + 1, => 1, + /* testMatchDefaultNestedInSwitchDefault */ + default, => 'default', + }; + /* testSwitchDefaultCloserMarker */ + break; + } +} + +function switchWithDefaultInMatch() { + $x = match ($y) { + 5, 8 => function($z) { + switch($z) { + case 'a'; + $var = [1, 2, 3]; + return 'a'; + /* testSwitchDefaultNestedInMatchCase */ + default: + $var = [1, 2, 3]; + return 'default1'; + } + }, + /* testMatchDefault */ + default => function($z) { + switch($z) { + case 'a': + $i = callMe($a, $b); + return 'b'; + /* testSwitchDefaultNestedInMatchDefault */ + default: + $i = callMe($a, $b); + return 'default2'; + } + } + }; +} + +function switchAndDefaultSharingScopeCloser($i) { + switch ($i): + /* testSwitchAndDefaultSharingScopeCloser */ + default: + echo 'one'; + /* testSwitchAndDefaultSharingScopeCloserScopeCloser */ + endswitch; +} + +function switchDefaultNestedIfWithAndWithoutBraces($i, $foo, $baz) { + switch ($i) { + /* testSwitchDefaultNestedIfWithAndWithoutBraces */ + default: + if ($foo) { + return true; + } elseif ($baz) + return true; + else { + echo 'else'; + } + /* testSwitchDefaultNestedIfWithAndWithoutBracesScopeCloser */ + break; + } +} + +function shortArrayWithConstantKey() { + $arr = [ + /* testClassConstantAsShortArrayKey */ + SomeClass::DEFAULT => 1, + /* testClassPropertyAsShortArrayKey */ + SomeClass->DEFAULT => 1, + /* testNamespacedConstantAsShortArrayKey */ + // Intentional parse error PHP < 8.0. Reserved keyword used as namespaced constant. + SomeNamespace\DEFAULT => 1, + /* testFQNGlobalConstantAsShortArrayKey */ + // Intentional parse error in PHP < 8.0. Reserved keyword used as global constant. + \DEFAULT => 1, + ]; +} + +function longArrayWithConstantKey() { + $arr = array( + /* testClassConstantAsLongArrayKey */ + SomeClass::DEFAULT => 1, + ); +} + +function yieldWithConstantKey() { + /* testClassConstantAsYieldKey */ + yield SomeClass::DEFAULT => 1; +} + +function longArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKey */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ), + }, + ), + }; +} + +function shortArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKey */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ], + }, + ], + }; +} + + +function longArrayWithConstantKeyWithNestedMatch() { + return array( + /* testClassConstantAsLongArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInLongArray */ + DEFAULT => 'foo' + }, + ); +} + +function shortArrayWithConstantKeyWithNestedMatch() { + return [ + /* testClassConstantAsShortArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInShortArray */ + DEFAULT => 'foo' + }, + ]; +} + +function switchWithConstantNonDefault($i) { + switch ($i) { + /* testClassConstantInSwitchCase */ + case SomeClass::DEFAULT: + return 1; + + /* testClassPropertyInSwitchCase */ + case SomeClass->DEFAULT: + return 2; + + /* testNamespacedConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as constant. + case SomeNamespace\DEFAULT: + return 2; + + /* testNamespaceRelativeConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as global constant. + case namespace\DEFAULT: + return 2; + } +} + +class Foo { + /* testClassConstant */ + const DEFAULT = 'foo'; + + /* testMethodDeclaration */ + public function default() {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php new file mode 100644 index 000000000..9b40fe109 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php @@ -0,0 +1,487 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapDefaultKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + /** + * Condition stop tokens when `default` is used with curlies. + * + * @var array + */ + protected $conditionStopTokens = [ + T_BREAK, + T_CONTINUE, + T_EXIT, + T_GOTO, + T_RETURN, + T_THROW, + ]; + + + /** + * Test that match "default" tokens does not get scope indexes. + * + * Note: Cases and default structures within a match structure do *NOT* get case/default scope + * conditions, in contrast to case and default structures in switch control structures. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataMatchDefault + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testMatchDefault($testMarker, $testContent='default') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame( + T_MATCH_DEFAULT, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_MATCH_DEFAULT (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayNotHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is set. Marker: %s.', $testMarker) + ); + + }//end testMatchDefault() + + + /** + * Data provider. + * + * @see testMatchDefault() + * + * @return array> + */ + public static function dataMatchDefault() + { + return [ + 'simple_match_default' => [ + 'testMarker' => '/* testSimpleMatchDefault */', + ], + 'match_default_in_switch_case_1' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase1 */', + ], + 'match_default_in_switch_case_2' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase2 */', + ], + 'match_default_in_switch_default' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchDefault */', + ], + 'match_default_containing_switch' => [ + 'testMarker' => '/* testMatchDefault */', + ], + + 'match_default_with_nested_long_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_long_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_long_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInLongArray */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_short_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInShortArray */', + 'testContent' => 'DEFAULT', + ], + ]; + + }//end dataMatchDefault() + + + /** + * Test that switch "default" tokens do get the scope indexes. + * + * Note: Cases and default structures within a switch control structure *do* get case/default scope + * conditions. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $openerMarker The comment prefacing the scope opener token. + * @param string $closerMarker The comment prefacing the scope closer token. + * @param string|null $conditionStopMarker The expected offset in relation to the testMarker, after which tokens stop + * having T_DEFAULT as a scope condition. + * @param string $testContent The token content to look for. + * @param bool $sharedScopeCloser Whether to skip checking for the `scope_condition` of the + * scope closer. Needed when the default and switch + * structures share a scope closer. See + * https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/810. + * + * @dataProvider dataSwitchDefault + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testSwitchDefault($testMarker, $openerMarker, $closerMarker, $conditionStopMarker=null, $testContent='default', $sharedScopeCloser=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + $expectedScopeOpener = $this->getTargetToken($openerMarker, [T_COLON, T_OPEN_CURLY_BRACKET, T_SEMICOLON]); + $expectedScopeCloser = $this->getTargetToken($closerMarker, [T_BREAK, T_CLOSE_CURLY_BRACKET, T_RETURN, T_ENDSWITCH]); + + // Make sure we're looking at the right token. + $this->assertSame( + T_DEFAULT, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_DEFAULT (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is not set. Marker: %s.', $testMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is not set. Marker: %s.', $testMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is not set. Marker: %s.', $testMarker) + ); + $this->assertSame( + $token, + $tokenArray['scope_condition'], + sprintf('Scope condition is not the T_DEFAULT token. Marker: %s.', $testMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf('Scope opener of the T_DEFAULT token incorrect. Marker: %s.', $testMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf('Scope closer of the T_DEFAULT token incorrect. Marker: %s.', $testMarker) + ); + + $opener = $tokenArray['scope_opener']; + $this->assertArrayHasKey( + 'scope_condition', + $tokens[$opener], + sprintf('Opener scope condition is not set. Marker: %s.', $openerMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokens[$opener], + sprintf('Opener scope opener is not set. Marker: %s.', $openerMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokens[$opener], + sprintf('Opener scope closer is not set. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $token, + $tokens[$opener]['scope_condition'], + sprintf('Opener scope condition is not the T_DEFAULT token. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokens[$opener]['scope_opener'], + sprintf('T_DEFAULT opener scope opener token incorrect. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokens[$opener]['scope_closer'], + sprintf('T_DEFAULT opener scope closer token incorrect. Marker: %s.', $openerMarker) + ); + + $closer = $expectedScopeCloser; + + if ($sharedScopeCloser === false) { + $closer = $tokenArray['scope_closer']; + $this->assertArrayHasKey( + 'scope_condition', + $tokens[$closer], + sprintf('Closer scope condition is not set. Marker: %s.', $closerMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokens[$closer], + sprintf('Closer scope opener is not set. Marker: %s.', $closerMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokens[$closer], + sprintf('Closer scope closer is not set. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $token, + $tokens[$closer]['scope_condition'], + sprintf('Closer scope condition is not the T_DEFAULT token. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokens[$closer]['scope_opener'], + sprintf('T_DEFAULT closer scope opener token incorrect. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokens[$closer]['scope_closer'], + sprintf('T_DEFAULT closer scope closer token incorrect. Marker: %s.', $closerMarker) + ); + }//end if + + if (($opener + 1) !== $closer) { + $end = $closer; + if (isset($conditionStopMarker) === true) { + $end = ( $this->getTargetToken($conditionStopMarker, $this->conditionStopTokens) + 1); + } + + for ($i = ($opener + 1); $i < $end; $i++) { + $this->assertArrayHasKey( + $token, + $tokens[$i]['conditions'], + sprintf('T_DEFAULT condition not added for token belonging to the T_DEFAULT structure. Marker: %s.', $testMarker) + ); + } + }//end if + + }//end testSwitchDefault() + + + /** + * Data provider. + * + * @see testSwitchDefault() + * + * @return array> + */ + public static function dataSwitchDefault() + { + return [ + 'simple_switch_default' => [ + 'testMarker' => '/* testSimpleSwitchDefault */', + 'openerMarker' => '/* testSimpleSwitchDefault */', + 'closerMarker' => '/* testSimpleSwitchDefault */', + ], + 'simple_switch_default_with_curlies' => [ + // For a default structure with curly braces, the scope opener + // will be the open curly and the closer the close curly. + // However, scope conditions will not be set for open to close, + // but only for the open token up to the "break/return/continue" etc. + 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', + 'openerMarker' => '/* testSimpleSwitchDefaultWithCurliesScopeOpener */', + 'closerMarker' => '/* testSimpleSwitchDefaultWithCurliesScopeCloser */', + 'conditionStopMarker' => '/* testSimpleSwitchDefaultWithCurliesConditionStop */', + ], + 'switch_default_toplevel' => [ + 'testMarker' => '/* testSwitchDefault */', + 'openerMarker' => '/* testSwitchDefault */', + 'closerMarker' => '/* testSwitchDefaultCloserMarker */', + ], + 'switch_default_nested_in_match_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'openerMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'closerMarker' => '/* testSwitchDefaultNestedInMatchCase */', + ], + 'switch_default_nested_in_match_default' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'openerMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'closerMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + ], + 'switch_and_default_sharing_scope_closer' => [ + 'testMarker' => '/* testSwitchAndDefaultSharingScopeCloser */', + 'openerMarker' => '/* testSwitchAndDefaultSharingScopeCloser */', + 'closerMarker' => '/* testSwitchAndDefaultSharingScopeCloserScopeCloser */', + 'conditionStopMarker' => null, + 'testContent' => 'default', + 'sharedScopeCloser' => true, + ], + 'switch_and_default_with_nested_if_with_and_without_braces' => [ + 'testMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBraces */', + 'openerMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBraces */', + 'closerMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBracesScopeCloser */', + ], + ]; + + }//end dataSwitchDefault() + + + /** + * Test that a "default" keyword which is not a switch or match default, does not get the scope indexes. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotDefaultKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame( + T_STRING, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_STRING (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayNotHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is set. Marker: %s.', $testMarker) + ); + + }//end testNotDefaultKeyword() + + + /** + * Data provider. + * + * @see testNotDefaultKeyword() + * + * @return array> + */ + public static function dataNotDefaultKeyword() + { + return [ + 'class-constant-as-short-array-key' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKey */', + ], + 'class-property-as-short-array-key' => [ + 'testMarker' => '/* testClassPropertyAsShortArrayKey */', + ], + 'namespaced-constant-as-short-array-key' => [ + 'testMarker' => '/* testNamespacedConstantAsShortArrayKey */', + ], + 'fqn-global-constant-as-short-array-key' => [ + 'testMarker' => '/* testFQNGlobalConstantAsShortArrayKey */', + ], + 'class-constant-as-long-array-key' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKey */', + ], + 'class-constant-as-yield-key' => [ + 'testMarker' => '/* testClassConstantAsYieldKey */', + ], + + 'class-constant-as-long-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatch */', + ], + 'class-constant-as-long-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-short-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatch */', + ], + 'class-constant-as-short-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-long-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyWithNestedMatch */', + ], + 'class-constant-as-short-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyWithNestedMatch */', + ], + + 'class-constant-in-switch-case' => [ + 'testMarker' => '/* testClassConstantInSwitchCase */', + ], + 'class-property-in-switch-case' => [ + 'testMarker' => '/* testClassPropertyInSwitchCase */', + ], + 'namespaced-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespacedConstantInSwitchCase */', + ], + 'namespace-relative-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespaceRelativeConstantInSwitchCase */', + ], + + 'class-constant-declaration' => [ + 'testMarker' => '/* testClassConstant */', + ], + 'class-method-declaration' => [ + 'testMarker' => '/* testMethodDeclaration */', + 'testContent' => 'default', + ], + ]; + + }//end dataNotDefaultKeyword() + + + /** + * Test a specific edge case where a scope opener would be incorrectly set. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3326 + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testIssue3326() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testClassConstant */', [T_SEMICOLON]); + $tokenArray = $tokens[$token]; + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testIssue3326() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc new file mode 100644 index 000000000..e303c3850 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc @@ -0,0 +1,13 @@ + + * @author Rodrigo Primo + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapIfKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_IF token with nested case statement missing break statement. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-fddc61a + * + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testIfElseWithNestedCaseMissingBreakSharedClosers() + { + + $tokens = $this->phpcsFile->getTokens(); + $ifTestMarker = '/* testIfElseWithNestedCaseMissingBreak */'; + $ifCloserTestMarker = '/* testIfElseWithNestedCaseMissingBreakCloser */'; + $ifTokenIndex = $this->getTargetToken($ifTestMarker, T_IF); + $tokenArray = $tokens[$ifTokenIndex]; + + $expectedScopeCondition = $ifTokenIndex; + $expectedScopeOpener = $this->getTargetToken($ifTestMarker, T_COLON); + $expectedScopeCloser = $this->getTargetToken($ifCloserTestMarker, T_ELSE); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_IF, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testIfElseWithNestedCaseMissingBreakSharedClosers() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc new file mode 100644 index 000000000..6df910bed --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc @@ -0,0 +1,60 @@ + $obj->{$foo . $bar})()) /* testSwitchArrowFunctionWithinConditionScopeOpener */ { + case 1: + return 'test'; +/* testSwitchArrowFunctionWithinConditionScopeCloser */ +} + +/* testSwitchArrowFunctionWithReturnTypeWithinCondition */ +switch((fn(): string => $condition ? 'foo' : 'bar')()) /* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeOpener */ : + /* testSwitchArrowFunctionWithReturnTypeWithinConditionEnsureTestWillNotPickUpWrongColon */ + case 1: + return 'test'; +/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeCloser */ +endswitch; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php new file mode 100644 index 000000000..dd6634ace --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php @@ -0,0 +1,160 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapSwitchTokenScopeTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_SWITCH token (normal and alternative syntax). + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testOpenerMarker Optional. The comment which prefaces the scope opener if different + * from the test marker. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-b24b96b + * + * @dataProvider dataSwitchScope + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testSwitchScope($testMarker, $expectedTokens, $testOpenerMarker=null, $testCloserMarker=null) + { + $tokens = $this->phpcsFile->getTokens(); + $switchIndex = $this->getTargetToken($testMarker, [T_SWITCH]); + $tokenArray = $tokens[$switchIndex]; + + $scopeOpenerMarker = $testMarker; + if (isset($testOpenerMarker) === true) { + $scopeOpenerMarker = $testOpenerMarker; + } + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $switchIndex; + $expectedScopeOpener = $this->getTargetToken($scopeOpenerMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_SWITCH, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testSwitchScope() + + + /** + * Data provider. + * + * @see testSwitchScope() + * + * @return array|null>> + */ + public static function dataSwitchScope() + { + return [ + 'switch normal syntax' => [ + 'testMarker' => '/* testSwitchNormalSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => null, + 'testCloserMarker' => '/* testSwitchNormalSyntaxScopeCloser */', + ], + 'switch alternative syntax' => [ + 'testMarker' => '/* testSwitchAlternativeSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => null, + 'testCloserMarker' => '/* testSwitchAlternativeSyntaxScopeCloser */', + ], + 'switch with closure in the condition' => [ + 'testMarker' => '/* testSwitchClosureWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => '/* testSwitchClosureWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchClosureWithinConditionScopeCloser */', + ], + 'switch alternative syntax with closure containing return type in the condition' => [ + 'testMarker' => '/* testSwitchClosureWithReturnTypeWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => '/* testSwitchClosureWithReturnTypeWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchClosureWithReturnTypeWithinConditionScopeCloser */', + ], + 'switch with arrow function in the condition' => [ + 'testMarker' => '/* testSwitchArrowFunctionWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => '/* testSwitchArrowFunctionWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchArrowFunctionWithinConditionScopeCloser */', + ], + 'switch alternative syntax with arrow function containing return type in the condition' => [ + 'testMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeCloser */', + ], + + ]; + + }//end dataSwitchScope() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php new file mode 100644 index 000000000..c6acda727 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php @@ -0,0 +1,98 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapWithNamespaceOperatorTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the scope opener/closers are set correctly when the namespace keyword is encountered as an operator. + * + * @param string $testMarker The comment which prefaces the target tokens in the test file. + * @param array $tokenTypes The token type to search for. + * @param array $open Optional. The token type for the scope opener. + * @param array $close Optional. The token type for the scope closer. + * + * @dataProvider dataScopeSetting + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testScopeSetting($testMarker, $tokenTypes, $open=[T_OPEN_CURLY_BRACKET], $close=[T_CLOSE_CURLY_BRACKET]) + { + $tokens = $this->phpcsFile->getTokens(); + + $target = $this->getTargetToken($testMarker, $tokenTypes); + $opener = $this->getTargetToken($testMarker, $open); + $closer = $this->getTargetToken($testMarker, $close); + + $this->assertArrayHasKey('scope_opener', $tokens[$target], 'Scope opener missing'); + $this->assertArrayHasKey('scope_closer', $tokens[$target], 'Scope closer missing'); + $this->assertSame($opener, $tokens[$target]['scope_opener'], 'Scope opener not same'); + $this->assertSame($closer, $tokens[$target]['scope_closer'], 'Scope closer not same'); + + $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Scope opener missing for open curly'); + $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Scope closer missing for open curly'); + $this->assertSame($opener, $tokens[$opener]['scope_opener'], 'Scope opener not same for open curly'); + $this->assertSame($closer, $tokens[$opener]['scope_closer'], 'Scope closer not same for open curly'); + + $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Scope opener missing for close curly'); + $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Scope closer missing for close curly'); + $this->assertSame($opener, $tokens[$closer]['scope_opener'], 'Scope opener not same for close curly'); + $this->assertSame($closer, $tokens[$closer]['scope_closer'], 'Scope closer not same for close curly'); + + }//end testScopeSetting() + + + /** + * Data provider. + * + * @see testScopeSetting() + * + * @return array>> + */ + public static function dataScopeSetting() + { + return [ + 'class which extends namespace relative name' => [ + 'testMarker' => '/* testClassExtends */', + 'tokenTypes' => [T_CLASS], + ], + 'class which implements namespace relative name' => [ + 'testMarker' => '/* testClassImplements */', + 'tokenTypes' => [T_ANON_CLASS], + ], + 'interface which extend namespace relative name' => [ + 'testMarker' => '/* testInterfaceExtends */', + 'tokenTypes' => [T_INTERFACE], + ], + 'namespace relative name in function return type' => [ + 'testMarker' => '/* testFunctionReturnType */', + 'tokenTypes' => [T_FUNCTION], + ], + 'namespace relative name in closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'tokenTypes' => [T_CLOSURE], + ], + 'namespace relative name in arrow function return type' => [ + 'testMarker' => '/* testArrowFunctionReturnType */', + 'tokenTypes' => [T_FN], + 'open' => [T_FN_ARROW], + 'close' => [T_SEMICOLON], + ], + ]; + + }//end dataScopeSetting() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php new file mode 100644 index 000000000..f4bd711a6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php @@ -0,0 +1,124 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Miscellaneous tests for tab replacement. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenMiscTest extends TestCase +{ + + + /** + * Test that when no tab width is set or passed, the tab width will be set to 1. + * + * @return void + */ + public function testTabWidthNotSet() + { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_WHITESPACE, 0); + + // Verify initial state. + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame(' ', $tokens[$target]['content'], 'Content after initial parsing does not contain tabs'); + $this->assertSame(2, $tokens[$target]['length'], 'Length after initial parsing is not as expected'); + $this->assertArrayNotHasKey('orig_content', $tokens[$target], "Key 'orig_content' found in the initial token array."); + + $phpcsFile->tokenizer->replaceTabsInToken($tokens[$target]); + + // Verify tab replacement. + $this->assertSame(' ', $tokens[$target]['content'], 'Content after tab replacement is not as expected'); + $this->assertSame(2, $tokens[$target]['length'], 'Length after tab replacement is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + + }//end testTabWidthNotSet() + + + /** + * Test that the length calculation handles text in non-ascii encodings correctly. + * + * @requires extension iconv + * + * @return void + */ + public function testLengthSettingRespectsEncoding() + { + $config = new ConfigDouble(); + $config->tabWidth = 4; + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, 0); + + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame("'пасха пасха'", $tokens[$target]['content'], 'Content is not as expected'); + $this->assertSame(17, $tokens[$target]['length'], 'Length is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + $this->assertSame("'пасха пасха'", $tokens[$target]['orig_content'], 'Orig_content is not as expected'); + + }//end testLengthSettingRespectsEncoding() + + + /** + * Test that the length calculation falls back to byte length if iconv detects an illegal character. + * + * @requires extension iconv + * + * @return void + */ + public function testLengthSettingFallsBackToBytesWhenTextContainsIllegalChars() + { + $config = new ConfigDouble(); + $config->tabWidth = 4; + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, 0); + + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame(11, $tokens[$target]['length'], 'Length is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + + }//end testLengthSettingFallsBackToBytesWhenTextContainsIllegalChars() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php new file mode 100644 index 000000000..296215345 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 1. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth1Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 1; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 2, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 3, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 24, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 15, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 27, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 20, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 31, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php new file mode 100644 index 000000000..92de221d8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 2. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth2Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 2; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 26, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 17, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 34, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 23, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 32, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 53, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 48, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php new file mode 100644 index 000000000..5f7418798 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 4. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth4Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 4; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 8, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 6, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 17, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 32, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 21, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 48, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 25, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 36, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 53, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php new file mode 100644 index 000000000..361894fb9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 5. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth5Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 5; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 10, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 7, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 25, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 24, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 54, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 30, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 35, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 55, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 49, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc new file mode 100644 index 000000000..e6046500e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc @@ -0,0 +1,46 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use Exception; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tab replacement test case. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +abstract class ReplaceTabsInTokenTestCase extends AbstractTokenizerTestCase +{ + + /** + * The name of the test case file used by this test. + * + * @var string + */ + private static $caseFileName; + + + /** + * Make a copy the test case file we want to use for this test (as the file will be used by multiple tests). + * + * @beforeClass + * + * @return void + * + * @throws \Exception In case the base test case file would not be available. + */ + public static function copyCaseFile() + { + $relativeCN = str_replace(__NAMESPACE__.'\\', '', get_called_class()); + self::$caseFileName = __DIR__.DIRECTORY_SEPARATOR.$relativeCN.'.inc'; + + $baseFileName = realpath(__DIR__.'/ReplaceTabsInTokenTest.inc'); + if (is_string($baseFileName) === false) { + throw new Exception('Base test case file "ReplaceTabsInTokenTest.inc" not found'); + } + + if (copy($baseFileName, self::$caseFileName) === false) { + throw new Exception(sprintf('Failed to copy test case file "ReplaceTabsInTokenTest.inc" to %s', self::$caseFileName)); + } + + }//end copyCaseFile() + + + /** + * Delete the copied test case file after use. + * + * @afterClass + * + * @return void + */ + public static function deleteCaseFile() + { + @unlink(self::$caseFileName); + + }//end deleteCaseFile() + + + /** + * Verify that if a token not containing tabs would be passed to the replaceTabsInToken() method, + * yes, the `orig_content` key is added, but no changes are made to the token `content` or `length` values. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|string $testTarget Token code to look for. + * @param array $expected Expectations for the token array. + * @param int $offset Optional. Offset from the target token to get to the _real_ target. + * This is specifically needed to target indentation whitespace. + * + * @dataProvider dataNoReplacementsAreMadeWhenNoTabsAreFound + * + * @return void + */ + public function testNoReplacementsAreMadeWhenNoTabsAreFound($testMarker, $testTarget, $expected, $offset=0) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, $testTarget); + $target += $offset; + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testNoReplacementsAreMadeWhenNoTabsAreFound() + + + /** + * Data provider. + * + * @see testNoReplacementsAreMadeWhenNoTabsAreFound() + * + * @return array>> + */ + public static function dataNoReplacementsAreMadeWhenNoTabsAreFound() + { + return [ + 'Indentation whitespace, only spaces' => [ + 'testMarker' => '/* testNoReplacementNeeded */', + 'testTarget' => T_WHITESPACE, + 'expected' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => null, + ], + 'offset' => 1, + ], + 'Trailing comment not containing any tabs' => [ + 'testMarker' => '/* testNoReplacementNeeded */', + 'testTarget' => T_COMMENT, + 'expected' => [ + 'length' => 35, + 'content' => '// Comment not containing any tabs. +', + 'orig_content' => null, + ], + ], + ]; + + }//end dataNoReplacementsAreMadeWhenNoTabsAreFound() + + + /** + * Test tab replacement in tokens. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|string $testTarget Token code to look for. + * @param array $expected Expectations for the token array. + * @param int $offset Optional. Offset from the target token to get to the _real_ target. + * This is specifically needed to target indentation whitespace. + * + * @dataProvider dataTabReplacement + * + * @return void + */ + public function testTabReplacement($testMarker, $testTarget, $expected, $offset=0) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, $testTarget); + $target += $offset; + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testTabReplacement() + + + /** + * Data provider. + * + * @see testTabReplacement() + * + * @return array>> + * + * @throws \Exception When the getTabReplacementExpected() method doesn't provide data in the correct format. + */ + public static function dataTabReplacement() + { + $data = [ + 'Tab indentation' => [ + 'testMarker' => '/* testTabIndentation */', + 'testTarget' => T_WHITESPACE, + ], + 'Mixed tab/space indentation' => [ + 'testMarker' => '/* testMixedIndentation */', + 'testTarget' => T_WHITESPACE, + ], + 'Inline: single tab in text string' => [ + 'testMarker' => '/* testInlineSingleTab */', + 'testTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'Inline: single tab between each word in text string' => [ + 'testMarker' => '/* testInlineSingleTabBetweenEachWord */', + 'testTarget' => T_DOUBLE_QUOTED_STRING, + ], + 'Inline: multiple tabs in heredoc' => [ + 'testMarker' => '/* testInlineMultiTab */', + 'testTarget' => T_HEREDOC, + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'testMarker' => '/* testInlineMultipleTabsBetweenEachWord */', + 'testTarget' => T_NOWDOC, + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'testMarker' => '/* testInlineMixedSpacesTabs */', + 'testTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'testMarker' => '/* testInlineMixedSpacesTabsBetweenEachWord */', + 'testTarget' => T_DOUBLE_QUOTED_STRING, + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize1 */', + 'testTarget' => T_COMMENT, + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize2 */', + 'testTarget' => T_COMMENT, + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize3 */', + 'testTarget' => T_DOC_COMMENT_STRING, + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize4 */', + 'testTarget' => T_COMMENT, + ], + ]; + + $expectations = static::getTabReplacementExpected(); + + foreach ($data as $key => $value) { + if (isset($expectations[$key]) === false || is_array($expectations[$key]) === false) { + throw new Exception( + sprintf('Invalid getTabReplacementExpected() method. Missing expectation array for the "%s" test case', $key) + ); + } + + if (isset($expectations[$key]['length'], $expectations[$key]['content']) === false + || array_key_exists('orig_content', $expectations[$key]) === false + ) { + throw new Exception( + sprintf('Invalid expectation array for the "%s" test case. The array must contain the "length", "content" and "orig_content" keys', $key) + ); + } + + $data[$key]['expected'] = $expectations[$key]; + } + + // Set offset for test cases targetting whitespace. + $data['Tab indentation']['offset'] = 1; + $data['Mixed tab/space indentation']['offset'] = 1; + + return $data; + + }//end dataTabReplacement() + + + /** + * Data provider helper. + * + * Should be declared in child classes to set the expectations for the token array. + * + * @see dataTabReplacement() + * + * @return array> + */ + abstract public static function getTabReplacementExpected(); + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php new file mode 100644 index 000000000..2844c4a32 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php @@ -0,0 +1,91 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::escapeshellcmd() method. + * + * @covers \PHP_CodeSniffer\Util\Common::escapeshellcmd + * @group Windows + */ +final class EscapeshellcmdTest extends TestCase +{ + + + /** + * Test escaping shell commands. + * + * @param string $command The command provided. + * @param string $expected Expected function output. + * @param string $expectedWin Optional. Expected function output on Windows. + * Only needs to be passed if the output on Windows would be different. + * + * @dataProvider dataEscapeshellcmd + * + * @return void + */ + public function testEscapeshellcmd($command, $expected, $expectedWin=null) + { + if (stripos(PHP_OS, 'WIN') === 0 && empty($expectedWin) === false) { + $expected = $expectedWin; + } + + $this->assertSame($expected, Common::escapeshellcmd($command)); + + }//end testEscapeshellcmd() + + + /** + * Data provider. + * + * Note: we're only testing the PHPCS functionality, not the PHP native `escapeshellcmd()` + * function (as that's not our responsibility). + * + * @see testEscapeshellcmd() + * + * @return array> + */ + public static function dataEscapeshellcmd() + { + return [ + 'Command is empty string' => [ + 'command' => '', + 'expected' => '', + ], + 'Command is simple string' => [ + 'command' => 'csslint', + 'expected' => 'csslint', + ], + 'Command containing characters which PHP escapes' => [ + 'command' => '&#;`|*?~<>^()[]{}$\,%!', + 'expected' => '\&\#\;\`\|\*\?\~\<\>\^\(\)\[\]\{\}\$\\\\,%!', + 'expectedWin' => '^&^#^;^`^|^*^?^~^<^>^^^(^)^[^]^{^}^$^\,^%^!', + ], + // @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3214 + 'Command containing spaces, which can cause problems on Windows' => [ + 'command' => 'C:\Program Files\nodejs\csslint.cmd', + 'expected' => 'C:\\\\Program Files\\\\nodejs\\\\csslint.cmd', + 'expectedWin' => 'C:^\Program^ Files^\nodejs^\csslint.cmd', + ], + // @link https://github.com/php/doc-en/pull/511 + 'Command containing spaces with additional arguments' => [ + 'command' => 'php -f ./~home/path to/file.php', + 'expected' => 'php -f ./\~home/path to/file.php', + 'expectedWin' => 'php^ -f^ ./^~home/path^ to/file.php', + ], + ]; + + }//end dataEscapeshellcmd() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php new file mode 100644 index 000000000..444ea5eb0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php @@ -0,0 +1,212 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::getSniffCode() method. + * + * @covers \PHP_CodeSniffer\Util\Common::getSniffCode + */ +final class GetSniffCodeTest extends TestCase +{ + + + /** + * Test receiving an expected exception when the $sniffClass parameter is not passed a string value or is passed an empty string. + * + * @param mixed $input NOT a fully qualified sniff class name. + * + * @dataProvider dataGetSniffCodeThrowsExceptionOnInvalidInput + * + * @return void + */ + public function testGetSniffCodeThrowsExceptionOnInvalidInput($input) + { + $exception = 'InvalidArgumentException'; + $message = 'The $sniffClass parameter must be a non-empty string'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + Common::getSniffCode($input); + + }//end testGetSniffCodeThrowsExceptionOnInvalidInput() + + + /** + * Data provider. + * + * @see testGetSniffCodeThrowsExceptionOnInvalidInput() + * + * @return array> + */ + public static function dataGetSniffCodeThrowsExceptionOnInvalidInput() + { + return [ + 'Class name is not a string' => [true], + 'Class name is empty' => [''], + ]; + + }//end dataGetSniffCodeThrowsExceptionOnInvalidInput() + + + /** + * Test receiving an expected exception when the $sniffClass parameter is not passed a value which + * could be a fully qualified sniff(test) class name. + * + * @param string $input String input which can not be a fully qualified sniff(test) class name. + * + * @dataProvider dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass + * + * @return void + */ + public function testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass($input) + { + $exception = 'InvalidArgumentException'; + $message = 'The $sniffClass parameter was not passed a fully qualified sniff(test) class name. Received:'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + Common::getSniffCode($input); + + }//end testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + + + /** + * Data provider. + * + * @see testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + * + * @return array> + */ + public static function dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + { + return [ + 'Unqualified class name' => ['ClassName'], + 'Fully qualified class name, not enough parts' => ['Fully\\Qualified\\ClassName'], + 'Fully qualified class name, doesn\'t end on Sniff or UnitTest' => ['Fully\\Sniffs\\Qualified\\ClassName'], + ]; + + }//end dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + + + /** + * Test transforming a sniff class name to a sniff code. + * + * @param string $fqnClass A fully qualified sniff class name. + * @param string $expected Expected function output. + * + * @dataProvider dataGetSniffCode + * + * @return void + */ + public function testGetSniffCode($fqnClass, $expected) + { + $this->assertSame($expected, Common::getSniffCode($fqnClass)); + + }//end testGetSniffCode() + + + /** + * Data provider. + * + * @see testGetSniffCode() + * + * @return array> + */ + public static function dataGetSniffCode() + { + return [ + 'PHPCS native sniff' => [ + 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Arrays\\ArrayIndentSniff', + 'expected' => 'Generic.Arrays.ArrayIndent', + ], + 'Class is a PHPCS native test class' => [ + 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Tests\\Arrays\\ArrayIndentUnitTest', + 'expected' => 'Generic.Arrays.ArrayIndent', + ], + 'Sniff in external standard without namespace prefix' => [ + 'fqnClass' => 'MyStandard\\Sniffs\\PHP\\MyNameSniff', + 'expected' => 'MyStandard.PHP.MyName', + ], + 'Test in external standard without namespace prefix' => [ + 'fqnClass' => 'MyStandard\\Tests\\PHP\\MyNameUnitTest', + 'expected' => 'MyStandard.PHP.MyName', + ], + 'Sniff in external standard with namespace prefix' => [ + 'fqnClass' => 'Vendor\\Package\\MyStandard\\Sniffs\\Category\\AnalyzeMeSniff', + 'expected' => 'MyStandard.Category.AnalyzeMe', + ], + 'Test in external standard with namespace prefix' => [ + 'fqnClass' => 'Vendor\\Package\\MyStandard\\Tests\\Category\\AnalyzeMeUnitTest', + 'expected' => 'MyStandard.Category.AnalyzeMe', + ], + + /* + * These are not valid sniff codes and is an undesirable result, but can't be helped + * as changing this would be a BC-break. + * Supporting these to allow for tags directly including sniff files. + * See: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/675 + */ + + 'Fully qualified class name, ends on Sniff, but isn\'t' => [ + 'fqnClass' => 'Fully\\Sniffs\\AbstractSomethingSniff', + 'expected' => '.Sniffs.AbstractSomething', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [1]' => [ + 'fqnClass' => 'CheckMeSniff', + 'expected' => '..CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [2]' => [ + 'fqnClass' => 'CompanyName\\CheckMeSniff', + 'expected' => '.CompanyName.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [3]' => [ + 'fqnClass' => 'CompanyName\\Sniffs\\CheckMeSniff', + 'expected' => '.Sniffs.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [4]' => [ + 'fqnClass' => 'CompanyName\\CustomSniffs\\Whatever\\CheckMeSniff', + 'expected' => 'CompanyName.Whatever.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [5]' => [ + 'fqnClass' => 'CompanyName\\Sniffs\\Category\\Sniff', + 'expected' => 'CompanyName.Category.', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [6]' => [ + 'fqnClass' => 'CompanyName\\Tests\\Category\\UnitTest', + 'expected' => 'CompanyName.Category.', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [7]' => [ + 'fqnClass' => 'Sniffs\\Category\\NamedSniff', + 'expected' => '.Category.Named', + ], + ]; + + }//end dataGetSniffCode() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/IsCamelCapsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php similarity index 93% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/IsCamelCapsTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php index b60d524b0..951d76187 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/IsCamelCapsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php @@ -4,15 +4,20 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core; +namespace PHP_CodeSniffer\Tests\Core\Util\Common; use PHP_CodeSniffer\Util\Common; use PHPUnit\Framework\TestCase; -class IsCamelCapsTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Util\Common::isCamelCaps method. + * + * @covers \PHP_CodeSniffer\Util\Common::isCamelCaps + */ +final class IsCamelCapsTest extends TestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php new file mode 100644 index 000000000..8eb2fc22f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php @@ -0,0 +1,113 @@ +assertSame($expected, Common::prepareForOutput($content, $exclude)); + + }//end testPrepareForOutput() + + + /** + * Test formatting whitespace characters, on Windows. + * + * @param string $content The content to prepare. + * @param string[] $exclude A list of characters to leave invisible. + * @param string $expected Expected function output (unused in this test). + * @param string $expectedWin Expected function output on Windows. + * + * @requires OS ^WIN.*. + * @dataProvider dataPrepareForOutput + * + * @return void + */ + public function testPrepareForOutputWindows($content, $exclude, $expected, $expectedWin) + { + $this->assertSame($expectedWin, Common::prepareForOutput($content, $exclude)); + + }//end testPrepareForOutputWindows() + + + /** + * Data provider. + * + * @see testPrepareForOutput() + * @see testPrepareForOutputWindows() + * + * @return array> + */ + public static function dataPrepareForOutput() + { + return [ + 'Special characters are replaced with their escapes' => [ + 'content' => "\r\n\t", + 'exclude' => [], + 'expected' => "\033[30;1m\\r\033[0m\033[30;1m\\n\033[0m\033[30;1m\\t\033[0m", + 'expectedWin' => "\\r\\n\\t", + ], + 'Spaces are replaced with a unique mark' => [ + 'content' => " ", + 'exclude' => [], + 'expected' => "\033[30;1m·\033[0m\033[30;1m·\033[0m\033[30;1m·\033[0m\033[30;1m·\033[0m", + 'expectedWin' => " ", + ], + 'Other characters are unaffected' => [ + 'content' => "{echo 1;}", + 'exclude' => [], + 'expected' => "{echo\033[30;1m·\033[0m1;}", + 'expectedWin' => "{echo 1;}", + ], + 'No replacements' => [ + 'content' => 'nothing-should-be-replaced', + 'exclude' => [], + 'expected' => 'nothing-should-be-replaced', + 'expectedWin' => 'nothing-should-be-replaced', + ], + 'Excluded whitespace characters are unaffected' => [ + 'content' => "\r\n\t ", + 'exclude' => [ + "\r", + "\n", + ], + 'expected' => "\r\n\033[30;1m\\t\033[0m\033[30;1m·\033[0m", + 'expectedWin' => "\r\n\\t ", + ], + ]; + + }//end dataPrepareForOutput() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php new file mode 100644 index 000000000..ff253b8b8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php @@ -0,0 +1,96 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::stripColors() method. + * + * @covers \PHP_CodeSniffer\Util\Common::stripColors + */ +final class StripColorsTest extends TestCase +{ + + + /** + * Test stripping color codes from a text. + * + * @param string $text The text provided. + * @param string $expected Expected function output. + * + * @dataProvider dataStripColors + * + * @return void + */ + public function testStripColors($text, $expected) + { + $this->assertSame($expected, Common::stripColors($text)); + + }//end testStripColors() + + + /** + * Data provider. + * + * @see testStripColors() + * + * @return array> + */ + public static function dataStripColors() + { + return [ + 'Text is empty' => [ + 'text' => '', + 'expected' => '', + ], + 'Text enclosed in color code' => [ + 'text' => "\033[36mSome text\033[0m", + 'expected' => 'Some text', + ], + 'Text containing color code' => [ + 'text' => "Some text \033[33mSome other text", + 'expected' => 'Some text Some other text', + ], + 'Text enclosed in color code, bold' => [ + 'text' => "\033[1;32mSome text\033[0m", + 'expected' => 'Some text', + ], + 'Text enclosed in color code, with escaped text' => [ + 'text' => "\033[30;1m\\n\033[0m", + 'expected' => '\n', + ], + 'Text enclosed in color code, bold, dark, italic' => [ + 'text' => "\033[1;2;3mtext\033[0m", + 'expected' => 'text', + ], + 'Text enclosed in color code, foreground color' => [ + 'text' => "\033[38;5;255mtext\033[0m", + 'expected' => 'text', + ], + 'Text enclosed in color code, foreground color and background color' => [ + 'text' => "\033[38;5;200;48;5;255mtext\033[0m", + 'expected' => 'text', + ], + 'Multiline text containing multiple color codes' => [ + 'text' => "First \033[36mSecond\033[0m +Third \033[1;2;3mFourth +Next line\033[0m Last", + 'expected' => 'First Second +Third Fourth +Next line Last', + ], + ]; + + }//end dataStripColors() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php new file mode 100644 index 000000000..48bb6df1d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php @@ -0,0 +1,224 @@ + + * @copyright 2019 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::suggestType() method. + * + * @covers \PHP_CodeSniffer\Util\Common::suggestType + */ +final class SuggestTypeTest extends TestCase +{ + + + /** + * Test passing an empty type to the suggestType() method. + * + * @return void + */ + public function testSuggestTypeEmpty() + { + $this->assertSame('', Common::suggestType('')); + + }//end testSuggestTypeEmpty() + + + /** + * Test passing one of the allowed types to the suggestType() method. + * + * @param string $varType The type. + * + * @dataProvider dataSuggestTypeAllowedType + * + * @return void + */ + public function testSuggestTypeAllowedType($varType) + { + $result = Common::suggestType($varType); + $this->assertSame($varType, $result); + + }//end testSuggestTypeAllowedType() + + + /** + * Data provider. + * + * @see testSuggestTypeAllowedType() + * + * @return array> + */ + public static function dataSuggestTypeAllowedType() + { + $data = []; + foreach (Common::$allowedTypes as $type) { + $data['Type: '.$type] = [$type]; + } + + return $data; + + }//end dataSuggestTypeAllowedType() + + + /** + * Test passing one of the allowed types in the wrong case to the suggestType() method. + * + * @param string $varType The type found. + * @param string $expected Expected suggested type. + * + * @dataProvider dataSuggestTypeAllowedTypeWrongCase + * + * @return void + */ + public function testSuggestTypeAllowedTypeWrongCase($varType, $expected) + { + $result = Common::suggestType($varType); + $this->assertSame($expected, $result); + + }//end testSuggestTypeAllowedTypeWrongCase() + + + /** + * Data provider. + * + * @see testSuggestTypeAllowedTypeWrongCase() + * + * @return array> + */ + public static function dataSuggestTypeAllowedTypeWrongCase() + { + $data = []; + foreach (Common::$allowedTypes as $type) { + $data['Mixed case: '.$type] = [ + 'varType' => ucfirst($type), + 'expected' => $type, + ]; + $data['Uppercase: '.$type] = [ + 'varType' => strtoupper($type), + 'expected' => $type, + ]; + } + + return $data; + + }//end dataSuggestTypeAllowedTypeWrongCase() + + + /** + * Test the suggestType() method for all other cases. + * + * @param string $varType The type found. + * @param string $expected Expected suggested type. + * + * @dataProvider dataSuggestTypeOther + * + * @return void + */ + public function testSuggestTypeOther($varType, $expected) + { + $result = Common::suggestType($varType); + $this->assertSame($expected, $result); + + }//end testSuggestTypeOther() + + + /** + * Data provider. + * + * @see testSuggestTypeOther() + * + * @return array> + */ + public static function dataSuggestTypeOther() + { + return [ + // Short forms. + 'Short form type: bool, lowercase' => [ + 'varType' => 'bool', + 'expected' => 'boolean', + ], + 'Short form type: bool, uppercase' => [ + 'varType' => 'BOOL', + 'expected' => 'boolean', + ], + 'Short form type: double, lowercase' => [ + 'varType' => 'double', + 'expected' => 'float', + ], + 'Short form type: real, mixed case' => [ + 'varType' => 'Real', + 'expected' => 'float', + ], + 'Short form type: double, mixed case' => [ + 'varType' => 'DoUbLe', + 'expected' => 'float', + ], + 'Short form type: int, lowercase' => [ + 'varType' => 'int', + 'expected' => 'integer', + ], + 'Short form type: int, uppercase' => [ + 'varType' => 'INT', + 'expected' => 'integer', + ], + + // Array types. + 'Array type: mixed case keyword, empty parentheses' => [ + 'varType' => 'Array()', + 'expected' => 'array', + ], + 'Array type: short form type as value within the parentheses' => [ + 'varType' => 'array(real)', + 'expected' => 'array(float)', + ], + 'Array type: short form type as key within the parentheses' => [ + 'varType' => 'array(int => object)', + 'expected' => 'array(integer => object)', + ], + 'Array type: valid specification' => [ + 'varType' => 'array(integer => array(string => resource))', + 'expected' => 'array(integer => array(string => resource))', + ], + 'Array type: short form + uppercase types within the parentheses' => [ + 'varType' => 'ARRAY(BOOL => DOUBLE)', + 'expected' => 'array(boolean => float)', + ], + 'Array type: no space around the arrow within the parentheses' => [ + 'varType' => 'array(string=>resource)', + 'expected' => 'array(string => resource)', + ], + + // Incomplete array type. + 'Array type: incomplete specification' => [ + 'varType' => 'array(int =>', + 'expected' => 'array', + ], + + // Custom types are returned unchanged. + 'Unknown type: " => "' => [ + 'varType' => ' => ', + 'expected' => ' => ', + ], + 'Unknown type: "string[]"' => [ + 'varType' => 'string[]', + 'expected' => 'string[]', + ], + 'Unknown type: "\DateTime"' => [ + 'varType' => '\DateTime', + 'expected' => '\DateTime', + ], + ]; + + }//end dataSuggestTypeOther() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php new file mode 100644 index 000000000..b3d51a5c7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php @@ -0,0 +1,769 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Help; + +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Util\Help; +use PHPUnit\Framework\TestCase; +use ReflectionMethod; +use ReflectionProperty; + +/** + * Test the Help class. + * + * @covers \PHP_CodeSniffer\Util\Help + */ +final class HelpTest extends TestCase +{ + + + /** + * QA check: verify that the category names are at most the minimum screen width + * and that option argument names are always at most half the length of the minimum screen width. + * + * If this test would start failing, either wrapping of argument info would need to be implemented + * or the minimum screen width needs to be upped. + * + * @coversNothing + * + * @return void + */ + public function testQaArgumentNamesAreWithinAcceptableBounds() + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'getAllOptions'); + $reflMethod->setAccessible(true); + $allOptions = $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->assertGreaterThan(0, count($allOptions), 'No categories found'); + + $minScreenWidth = Help::MIN_WIDTH; + $maxArgWidth = ($minScreenWidth / 2); + + foreach ($allOptions as $category => $options) { + $this->assertLessThanOrEqual( + Help::MIN_WIDTH, + strlen($category), + "Category name $category is longer than the minimum screen width of $minScreenWidth" + ); + + foreach ($options as $option) { + if (isset($option['argument']) === false) { + continue; + } + + $this->assertLessThanOrEqual( + $maxArgWidth, + strlen($option['argument']), + "Option name {$option['argument']} is longer than the half the minimum screen width of $minScreenWidth" + ); + } + } + + }//end testQaArgumentNamesAreWithinAcceptableBounds() + + + /** + * QA check: verify that each option only contains a spacer, text or argument + description combo. + * + * @coversNothing + * + * @return void + */ + public function testQaValidCategoryOptionDefinitions() + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'getAllOptions'); + $reflMethod->setAccessible(true); + $allOptions = $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->assertGreaterThan(0, count($allOptions), 'No categories found'); + + foreach ($allOptions as $category => $options) { + $this->assertGreaterThan(0, count($options), "No options found in category $category"); + + foreach ($options as $name => $option) { + if (isset($option['spacer']) === true) { + $this->assertStringStartsWith('blank-line', $name, 'The name for spacer items should start with "blank-line"'); + } + + $this->assertFalse( + isset($option['spacer'], $option['text']), + "Option $name: spacer and text should not be combined in one option" + ); + $this->assertFalse( + isset($option['spacer'], $option['argument']), + "Option $name: spacer and argument should not be combined in one option" + ); + $this->assertFalse( + isset($option['spacer'], $option['description']), + "Option $name: spacer and description should not be combined in one option" + ); + $this->assertFalse( + isset($option['text'], $option['argument']), + "Option $name: text and argument should not be combined in one option" + ); + $this->assertFalse( + isset($option['text'], $option['description']), + "Option $name: text and description should not be combined in one option" + ); + + if (isset($option['argument']) === true) { + $this->assertArrayHasKey( + 'description', + $option, + "Option $name: an argument should always be accompanied by a description" + ); + } + + if (isset($option['description']) === true) { + $this->assertArrayHasKey( + 'argument', + $option, + "Option $name: a description should always be accompanied by an argument" + ); + } + }//end foreach + }//end foreach + + }//end testQaValidCategoryOptionDefinitions() + + + /** + * Test receiving an expected exception when the shortOptions parameter is not passed a string value. + * + * @return void + */ + public function testConstructorInvalidArgumentException() + { + $exception = 'InvalidArgumentException'; + $message = 'The $shortOptions parameter must be a string'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new Help(new ConfigDouble(), [], []); + + }//end testConstructorInvalidArgumentException() + + + /** + * Test filtering of the options by requested options. + * + * Tests that: + * - Options not explicitly requested are removed. + * - Short options passed via the longOptions array are still respected. + * - A category gets removed if all options are removed, even if the category still has spacers. + * + * @param array $longOptions The long options which should be displayed. + * @param string $shortOptions The short options which should be displayed. + * @param array $expected The categories expected after filtering with the number + * of expected help items per category. + * + * @dataProvider dataOptionFiltering + * + * @return void + */ + public function testOptionFiltering($longOptions, $shortOptions, $expected) + { + $help = new Help(new ConfigDouble(), $longOptions, $shortOptions); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $activeOptions = $reflProperty->getValue($help); + $reflProperty->setAccessible(false); + + // Simplify the value to make it comparible. + foreach ($activeOptions as $category => $options) { + $activeOptions[$category] = count($options); + } + + $this->assertSame($expected, $activeOptions, 'Option count per category does not match'); + + }//end testOptionFiltering() + + + /** + * Data provider. + * + * @return array|array>> + */ + public static function dataOptionFiltering() + { + $allLongOptions = explode(',', Help::DEFAULT_LONG_OPTIONS); + $allLongOptions[] = 'cache'; + $allLongOptions[] = 'no-cache'; + $allLongOptions[] = 'report'; + $allLongOptions[] = 'report-file'; + $allLongOptions[] = 'report-report'; + $allLongOptions[] = 'runtime-set'; + $allLongOptions[] = 'config-explain'; + $allLongOptions[] = 'config-set'; + $allLongOptions[] = 'config-delete'; + $allLongOptions[] = 'config-show'; + $allLongOptions[] = 'generator'; + $allLongOptions[] = 'suffix'; + + $allShortOptions = Help::DEFAULT_SHORT_OPTIONS.'saem'; + + return [ + 'No options' => [ + 'longOptions' => [], + 'shortOptions' => '', + 'expected' => [], + ], + 'Invalid options have no influence' => [ + 'longOptions' => [ + 'doesnotexist', + 'invalid', + ], + 'shortOptions' => 'bjrz', + 'expected' => [], + ], + 'Short options passed as long options works fine' => [ + 'longOptions' => [ + 's', + 'suffix', + 'a', + 'e', + 'colors', + ], + 'shortOptions' => '', + 'expected' => [ + 'Rule Selection Options' => 1, + 'Run Options' => 2, + 'Reporting Options' => 2, + ], + ], + 'All options' => [ + 'longOptions' => $allLongOptions, + 'shortOptions' => $allShortOptions, + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 7, + 'Run Options' => 8, + 'Reporting Options' => 19, + 'Configuration Options' => 8, + 'Miscellaneous Options' => 5, + ], + ], + 'Default options only' => [ + 'longOptions' => explode(',', Help::DEFAULT_LONG_OPTIONS), + 'shortOptions' => Help::DEFAULT_SHORT_OPTIONS, + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 5, + 'Run Options' => 4, + 'Reporting Options' => 14, + 'Configuration Options' => 4, + 'Miscellaneous Options' => 5, + ], + ], + 'Only one category' => [ + 'longOptions' => [ + 'file', + 'stdin-path', + 'file-list', + 'filter', + 'ignore', + 'extensions', + ], + 'shortOptions' => '-l', + 'expected' => [ + 'Scan targets' => 8, + ], + ], + 'All except one category' => [ + 'longOptions' => array_diff($allLongOptions, ['version', 'vv', 'vvv']), + 'shortOptions' => str_replace(['h', 'v'], '', $allShortOptions), + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 7, + 'Run Options' => 8, + 'Reporting Options' => 19, + 'Configuration Options' => 8, + ], + ], + ]; + + }//end dataOptionFiltering() + + + /** + * Test filtering of the options by requested options does not leave stray spacers at the start + * or end of a category and that a category does not contain two consecutive spacers. + * + * {@internal Careful! This test may need updates to still test what it is supposed to test + * if/when the defined options in Help::getAllOptions() change.} + * + * @param array $longOptions The long options which should be displayed. + * @param string $shortOptions The short options which should be displayed. + * + * @dataProvider dataOptionFilteringSpacerHandling + * + * @return void + */ + public function testOptionFilteringSpacerHandling($longOptions, $shortOptions) + { + $help = new Help(new ConfigDouble(), $longOptions, $shortOptions); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $activeOptions = $reflProperty->getValue($help); + $reflProperty->setAccessible(false); + + $this->assertNotEmpty($activeOptions, 'Active options is empty, test is invalid'); + + foreach ($activeOptions as $options) { + $first = reset($options); + $this->assertArrayNotHasKey('spacer', $first, 'Found spacer at start of category'); + + $last = end($options); + $this->assertArrayNotHasKey('spacer', $last, 'Found spacer at end of category'); + + $previousWasSpacer = false; + foreach ($options as $option) { + $this->assertFalse((isset($option['spacer']) && $previousWasSpacer === true), 'Consecutive spacers found'); + $previousWasSpacer = isset($option['spacer']); + } + } + + }//end testOptionFilteringSpacerHandling() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataOptionFilteringSpacerHandling() + { + return [ + 'No spacer at start of category' => [ + 'longOptions' => ['generator'], + 'shortOptions' => 'ie', + ], + 'No spacer at end of category' => [ + 'longOptions' => [ + 'encoding', + 'tab-width', + ], + 'shortOptions' => '', + ], + 'No consecutive spacers within category' => [ + 'longOptions' => [ + 'report', + 'report-file', + 'report-report', + 'report-width', + 'basepath', + 'ignore-annotations', + 'colors', + 'no-colors', + ], + 'shortOptions' => 'spqm', + ], + ]; + + }//end dataOptionFilteringSpacerHandling() + + + /** + * Test that if no short/long options are passed, only usage information is displayed (CS mode). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @dataProvider dataDisplayUsage + * + * @return void + */ + public function testDisplayUsageCS($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcs', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCS() + + + /** + * Test that if no short/long options are passed, only usage information is displayed (CBF mode). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @dataProvider dataDisplayUsage + * @group CBF + * + * @return void + */ + public function testDisplayUsageCBF($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcbf', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCBF() + + + /** + * Helper method to test that if no short/long options are passed, only usage information is displayed + * (and displayed correctly). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @return void + */ + private function verifyDisplayUsage($cliArgs, $expectedRegex) + { + $help = new Help(new ConfigDouble($cliArgs), []); + + $this->expectOutputRegex($expectedRegex); + + $help->display(); + + }//end verifyDisplayUsage() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataDisplayUsage() + { + return [ + 'Usage without colors' => [ + 'cliArgs' => ['--no-colors'], + 'expectedRegex' => '`^\s*Usage:\s+phpc(bf|s) \[options\] \\s+$`', + ], + 'Usage with colors' => [ + 'cliArgs' => ['--colors'], + 'expectedRegex' => '`^\s*\\033\[33mUsage:\\033\[0m\s+phpc(bf|s) \[options\] \\s+$`', + ], + ]; + + }//end dataDisplayUsage() + + + /** + * Test the column width calculations. + * + * This tests the following aspects: + * 1. That the report width is never less than Help::MIN_WIDTH, even when a smaller width is passed. + * 2. That the first column width is calculated correctly and is based on the longest argument. + * 3. That the word wrapping of the description respects the maximum report width. + * 4. That if the description is being wrapped, the indent for the second line is calculated correctly. + * + * @param int $reportWidth Report width for the test. + * @param array $longOptions The long options which should be displayed. + * @param string $expectedOutput Expected output. + * + * @dataProvider dataReportWidthCalculations + * + * @return void + */ + public function testReportWidthCalculations($reportWidth, $longOptions, $expectedOutput) + { + $config = new ConfigDouble(["--report-width=$reportWidth", '--no-colors']); + $help = new Help($config, $longOptions); + + $reflMethod = new ReflectionMethod($help, 'printCategories'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->expectOutputString($expectedOutput); + + }//end testReportWidthCalculations() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataReportWidthCalculations() + { + $longOptions = [ + 'e', + 'generator', + ]; + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Report width small: 40; forces report width to minimum width of 60' => [ + 'reportWidth' => 40, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the'.PHP_EOL + .' names of all the sniffs it'.PHP_EOL + .' includes.'.PHP_EOL + .' --generator= Show documentation for a standard.'.PHP_EOL + .' Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width is minimum: 60 (= self::MIN_WIDTH)' => [ + 'reportWidth' => Help::MIN_WIDTH, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the'.PHP_EOL + .' names of all the sniffs it'.PHP_EOL + .' includes.'.PHP_EOL + .' --generator= Show documentation for a standard.'.PHP_EOL + .' Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width matches length for one line, not the other: 96; only one should wrap' => [ + 'reportWidth' => 96, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the names of all the sniffs it includes.'.PHP_EOL + .' --generator= Show documentation for a standard. Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width matches longest line: 119; the messages should not wrap and there should be no stray new line at the end' => [ + 'reportWidth' => 119, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the names of all the sniffs it includes.'.PHP_EOL + .' --generator= Show documentation for a standard. Use either the "HTML", "Markdown" or "Text" generator.'.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataReportWidthCalculations() + + + /** + * Verify that variable elements in an argument specification get colorized correctly. + * + * @param string $input String to colorize. + * @param string $expected Expected function output. + * + * @dataProvider dataColorizeVariableInput + * + * @return void + */ + public function testColorizeVariableInput($input, $expected) + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'colorizeVariableInput'); + $reflMethod->setAccessible(true); + $result = $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->assertSame($expected, $result); + + }//end testColorizeVariableInput() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataColorizeVariableInput() + { + return [ + 'Empty string' => [ + 'input' => '', + 'expected' => '', + ], + 'String without variable element(s)' => [ + 'input' => 'This is text', + 'expected' => 'This is text', + ], + 'String with variable element' => [ + 'input' => 'This text', + 'expected' => "This \033[36m\033[32m text", + ], + 'String with multiple variable elements' => [ + 'input' => ' is ', + 'expected' => "\033[36m\033[32m is \033[36m\033[32m", + ], + 'String with unclosed variable element' => [ + 'input' => 'This 'This [ + 'input' => ' text>', + 'expected' => "\033[36m text>\033[32m", + ], + 'String with nested elements and surrounding text' => [ + 'input' => 'Start text> end', + 'expected' => "Start \033[36m text>\033[32m end", + ], + ]; + + }//end dataColorizeVariableInput() + + + /** + * Test the various option types within a category get displayed correctly. + * + * @param array> $input The options to print. + * @param array $expectedRegex Regexes to validate expected output. + * + * @dataProvider dataPrintCategoryOptions + * + * @return void + */ + public function testPrintCategoryOptionsNoColor($input, $expectedRegex) + { + $config = new ConfigDouble(['--no-colors']); + $help = new Help($config, []); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($help, ['cat' => $input]); + $reflProperty->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'setMaxOptionNameLength'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'printCategoryOptions'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->expectOutputRegex($expectedRegex['no-color']); + + }//end testPrintCategoryOptionsNoColor() + + + /** + * Test the various option types within a category get displayed correctly. + * + * @param array> $input The options to print. + * @param array $expectedRegex Regexes to validate expected output. + * + * @dataProvider dataPrintCategoryOptions + * + * @return void + */ + public function testPrintCategoryOptionsColor($input, $expectedRegex) + { + $config = new ConfigDouble(['--colors']); + $help = new Help($config, []); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($help, ['cat' => $input]); + $reflProperty->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'setMaxOptionNameLength'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'printCategoryOptions'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->expectOutputRegex($expectedRegex['color']); + + }//end testPrintCategoryOptionsColor() + + + /** + * Data provider. + * + * @return array>|array>> + */ + public static function dataPrintCategoryOptions() + { + $indentLength = strlen(Help::INDENT); + $gutterLength = strlen(Help::GUTTER); + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Test readability is more important. + return [ + 'Input: arg, spacer, arg; new lines in description get preserved' => [ + 'input' => [ + 'short-option' => [ + 'argument' => '-a', + 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + ], + 'blank-line' => [ + 'spacer' => '', + ], + 'long-option-multi-line-description' => [ + 'argument' => '--something=', + 'description' => 'Proin sit amet malesuada libero, finibus bibendum tortor. Nulla vitae quam nec orci finibus pharetra.' + ."\n".'Nam eget blandit dui.', + ], + ], + 'expectedRegex' => [ + 'no-color' => '`^ {'.$indentLength.'}-a {15} {'.$gutterLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .'\R' + .' {'.$indentLength.'}--something= {'.$gutterLength.'}Proin sit amet malesuada libero, finibus bibendum tortor\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nulla vitae quam nec orci finibus pharetra\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nam eget blandit dui\.\R$`', + 'color' => '`^ {'.$indentLength.'}\\033\[32m-a {15}\\033\[0m {'.$gutterLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .'\R' + .' {'.$indentLength.'}\\033\[32m--something=\\033\[36m\\033\[32m\\033\[0m {'.$gutterLength.'}Proin sit amet malesuada libero, finibus bibendum tortor\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nulla vitae quam nec orci finibus pharetra\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nam eget blandit dui\.\R$`', + ], + ], + 'Input: text, arg, text; multi-line text gets wrapped' => [ + 'input' => [ + 'single-line-text' => [ + 'text' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + ], + 'argument-description' => [ + 'argument' => '--something', + 'description' => 'Fusce dapibus sodales est eu sodales.', + ], + 'multi-line-text-gets-wrapped' => [ + 'text' => 'Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in turpis auctor, consectetur ultrices lorem.', + ], + ], + 'expectedRegex' => [ + 'no-color' => '`^ {'.$indentLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .' {'.$indentLength.'}--something {'.$gutterLength.'}Fusce dapibus sodales est eu sodales\.\R' + .' {'.$indentLength.'}Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in\R' + .' {'.$indentLength.'}turpis auctor, consectetur ultrices lorem\.\R$`', + 'color' => '`^ {'.$indentLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .' {'.$indentLength.'}\\033\[32m--something\\033\[0m {'.$gutterLength.'}Fusce dapibus sodales est eu sodales\.\R' + .' {'.$indentLength.'}Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in\R' + .' {'.$indentLength.'}turpis auctor, consectetur ultrices lorem\.\R$`', + ], + ], + ]; + // phpcs:enable + + }//end dataPrintCategoryOptions() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php new file mode 100644 index 000000000..faa98ca41 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php @@ -0,0 +1,538 @@ +expectException($exception); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $exceptionMsg); + } + + $msgCollector = new MessageCollector(); + $msgCollector->add($message); + + }//end testAddingNonStringMessageResultsInException() + + + /** + * Data provider. + * + * @see testAddingNonStringMessageResultsInException() + * + * @return array> + */ + public static function dataAddingNonStringMessageResultsInException() + { + return [ + 'null' => [null], + 'boolean' => [true], + 'integer' => [10], + 'array' => [['something' => 'incorrect']], + ]; + + }//end dataAddingNonStringMessageResultsInException() + + + /** + * Verify that passing a message type which is not one of the predefined types is rejected with an exception. + * + * @param mixed $type The invalid "type" to pass. + * + * @dataProvider dataAddingMessageWithUnsupportedMessageTypeResultsInException + * + * @return void + */ + public function testAddingMessageWithUnsupportedMessageTypeResultsInException($type) + { + $exception = 'InvalidArgumentException'; + $exceptionMsg = 'The message $type should be one of the predefined MessageCollector constants. Received: '; + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $exceptionMsg); + } + + $msgCollector = new MessageCollector(); + $msgCollector->add('Message', $type); + + }//end testAddingMessageWithUnsupportedMessageTypeResultsInException() + + + /** + * Data provider. + * + * @see testAddingMessageWithUnsupportedMessageTypeResultsInException() + * + * @return array> + */ + public static function dataAddingMessageWithUnsupportedMessageTypeResultsInException() + { + return [ + 'null' => [null], + 'boolean' => [true], + 'string' => ['DEPRECATED'], + 'integer which doesn\'t match any of the message type constants: -235' => [-235], + 'integer which doesn\'t match any of the message type constants: 0' => [0], + 'integer which doesn\'t match any of the message type constants: 3' => [3], + 'integer which doesn\'t match any of the message type constants: 6' => [6], + 'integer which doesn\'t match any of the message type constants: 123' => [123], + 'integer which doesn\'t match any of the message type constants: PHP_INT_MAX' => [PHP_INT_MAX], + ]; + + }//end dataAddingMessageWithUnsupportedMessageTypeResultsInException() + + + /** + * Verify that the `containsBlockingErrors()` method correctly identifies whether the collected messages + * include messages which are blocking (errors), or only include non-blocking (warnings, notices, + * deprecations) messages. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param bool $expected The expected function output. + * + * @dataProvider dataContainsBlockingErrors + * + * @return void + */ + public function testContainsBlockingErrors($messages, $expected) + { + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->assertSame($expected, $msgCollector->containsBlockingErrors()); + + }//end testContainsBlockingErrors() + + + /** + * Data provider. + * + * @see testContainsBlockingErrors() + * + * @return array|bool>> + */ + public static function dataContainsBlockingErrors() + { + return [ + 'No messages' => [ + 'messages' => [], + 'expected' => false, + ], + 'Only non-blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::WARNING, + 'Second message' => MessageCollector::NOTICE, + 'Third message' => MessageCollector::DEPRECATED, + ], + 'expected' => false, + ], + 'Only blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::ERROR, + 'Second message' => MessageCollector::ERROR, + 'Third message' => MessageCollector::ERROR, + ], + 'expected' => true, + ], + 'Mix of blocking and non-blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::DEPRECATED, + 'Second message' => MessageCollector::ERROR, + 'Third message' => MessageCollector::WARNING, + ], + 'expected' => true, + ], + ]; + + }//end dataContainsBlockingErrors() + + + /** + * Test displaying non-blocking messages only. + * + * Verifies that: + * - Each message is prefixed with the appropriate prefix. + * - The default message order is observed. + * - The messages use the appropriate OS-specific EOL character. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param string $expected The expected exception message. + * + * @dataProvider dataDisplayingNonBlockingMessages + * + * @return void + */ + public function testDisplayingNonBlockingMessages($messages, $expected) + { + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testDisplayingNonBlockingMessages() + + + /** + * Data provider. + * + * @see testDisplayingNonBlockingMessages() + * + * @return array|string>> + */ + public static function dataDisplayingNonBlockingMessages() + { + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'No messages' => [ + 'messages' => [], + 'expected' => '', + ], + 'One warning' => [ + 'messages' => [ + 'This is a warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: This is a warning'.PHP_EOL.PHP_EOL, + ], + 'One notice' => [ + 'messages' => [ + 'This is a notice' => MessageCollector::NOTICE, + ], + 'expected' => 'NOTICE: This is a notice'.PHP_EOL.PHP_EOL, + ], + 'One deprecation' => [ + 'messages' => [ + 'This is a deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'DEPRECATED: This is a deprecation'.PHP_EOL.PHP_EOL, + ], + 'Multiple warnings' => [ + 'messages' => [ + 'First warning' => MessageCollector::WARNING, + 'Second warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: First warning'.PHP_EOL + .'WARNING: Second warning'.PHP_EOL.PHP_EOL, + ], + 'Multiple notices' => [ + 'messages' => [ + 'First notice' => MessageCollector::NOTICE, + 'Second notice' => MessageCollector::NOTICE, + 'Third notice' => MessageCollector::NOTICE, + ], + 'expected' => 'NOTICE: First notice'.PHP_EOL + .'NOTICE: Second notice'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL.PHP_EOL, + ], + 'Multiple deprecations' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'DEPRECATED: First deprecation'.PHP_EOL + .'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL, + ], + 'All together now' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second warning' => MessageCollector::WARNING, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: Second warning'.PHP_EOL + .'WARNING: Fourth warning'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL + .'DEPRECATED: First deprecation'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataDisplayingNonBlockingMessages() + + + /** + * Test displaying message collections containing blocking messages. + * + * Verifies that: + * - Each message is prefixed with the appropriate prefix. + * - The default message order is observed. + * - The messages use the appropriate OS-specific EOL character. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param string $expected The expected exception message. + * + * @dataProvider dataDisplayingBlockingErrors + * + * @return void + */ + public function testDisplayingBlockingErrors($messages, $expected) + { + $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($expected); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $expected); + } + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + $msgCollector->display(); + + }//end testDisplayingBlockingErrors() + + + /** + * Data provider. + * + * @see testDisplayingBlockingErrors() + * + * @return array|string>> + */ + public static function dataDisplayingBlockingErrors() + { + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Single error' => [ + 'messages' => [ + 'This is an error' => MessageCollector::ERROR, + ], + 'expected' => 'ERROR: This is an error'.PHP_EOL.PHP_EOL, + ], + 'Multiple errors' => [ + 'messages' => [ + 'First error' => MessageCollector::ERROR, + 'Second error' => MessageCollector::ERROR, + ], + 'expected' => 'ERROR: First error'.PHP_EOL + .'ERROR: Second error'.PHP_EOL.PHP_EOL, + ], + 'Errors mixed with non-blocking messages' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second warning' => MessageCollector::WARNING, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth error' => MessageCollector::ERROR, + 'Fifth warning' => MessageCollector::WARNING, + 'Sixth error' => MessageCollector::ERROR, + 'Seventh deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'ERROR: Fourth error'.PHP_EOL + .'ERROR: Sixth error'.PHP_EOL + .'WARNING: Second warning'.PHP_EOL + .'WARNING: Fifth warning'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL + .'DEPRECATED: First deprecation'.PHP_EOL + .'DEPRECATED: Seventh deprecation'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataDisplayingBlockingErrors() + + + /** + * Verify and safeguard that adding the same message twice is accepted when messages have different error levels. + * + * Note: have multiple messages with the exact same text is not great for conveying information + * to the end-user, but that's not the concern of the MessageCollector class. + * + * @return void + */ + public function testNonUniqueMessagesWithDifferentErrorLevelAreAccepted() + { + $message = 'Trying to add the same message twice'; + $msgCollector = new MessageCollector(); + $msgCollector->add($message, MessageCollector::NOTICE); + $msgCollector->add($message, MessageCollector::WARNING); + + $expected = 'WARNING: Trying to add the same message twice'.PHP_EOL; + $expected .= 'NOTICE: Trying to add the same message twice'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testNonUniqueMessagesWithDifferentErrorLevelAreAccepted() + + + /** + * Verify and safeguard that adding the same message twice is accepted when messages have the same error level. + * + * Note: have multiple messages with the exact same text is not great for conveying information + * to the end-user, but that's not the concern of the MessageCollector class. + * + * @return void + */ + public function testNonUniqueMessagesWithSameErrorLevelAreAccepted() + { + $message = 'Trying to add the same message twice'; + $msgCollector = new MessageCollector(); + $msgCollector->add($message, MessageCollector::NOTICE); + $msgCollector->add($message, MessageCollector::NOTICE); + + $expected = 'NOTICE: Trying to add the same message twice'.PHP_EOL; + $expected .= 'NOTICE: Trying to add the same message twice'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testNonUniqueMessagesWithSameErrorLevelAreAccepted() + + + /** + * Ensure that the message cache is cleared when the collected messages are displayed. + * + * @return void + */ + public function testCallingDisplayTwiceWillNotShowMessagesTwice() + { + $messages = [ + 'First notice' => MessageCollector::NOTICE, + 'Second deprecation' => MessageCollector::DEPRECATED, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ]; + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $expected = 'WARNING: Fourth warning'.PHP_EOL; + $expected .= 'NOTICE: First notice'.PHP_EOL; + $expected .= 'NOTICE: Third notice'.PHP_EOL; + $expected .= 'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + $msgCollector->display(); + + }//end testCallingDisplayTwiceWillNotShowMessagesTwice() + + + /** + * Test that messages are ordered correctly. + * + * @param string $order The display order. + * @param string $expected The expected output. + * + * @dataProvider dataDisplayOrderHandling + * + * @return void + */ + public function testDisplayOrderHandling($order, $expected) + { + $messages = [ + 'First notice' => MessageCollector::NOTICE, + 'Second deprecation' => MessageCollector::DEPRECATED, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ]; + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->expectOutputString($expected); + + $msgCollector->display($order); + + }//end testDisplayOrderHandling() + + + /** + * Data provider. + * + * @see testDisplayOrderHandling() + * + * @return array> + */ + public static function dataDisplayOrderHandling() + { + $expectedForSeverity = 'WARNING: Fourth warning'.PHP_EOL; + $expectedForSeverity .= 'NOTICE: First notice'.PHP_EOL; + $expectedForSeverity .= 'NOTICE: Third notice'.PHP_EOL; + $expectedForSeverity .= 'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL; + + $expectedForReceived = 'NOTICE: First notice'.PHP_EOL; + $expectedForReceived .= 'DEPRECATED: Second deprecation'.PHP_EOL; + $expectedForReceived .= 'NOTICE: Third notice'.PHP_EOL; + $expectedForReceived .= 'WARNING: Fourth warning'.PHP_EOL.PHP_EOL; + + return [ + 'Order by severity' => [ + 'order' => MessageCollector::ORDERBY_SEVERITY, + 'expected' => $expectedForSeverity, + ], + 'Order by received' => [ + 'order' => MessageCollector::ORDERBY_RECEIVED, + 'expected' => $expectedForReceived, + ], + 'Invalid order defaults to severity' => [ + 'order' => 'unknown order', + 'expected' => $expectedForSeverity, + ], + ]; + + }//end dataDisplayOrderHandling() + + + /** + * Test helper. + * + * @param \PHP_CodeSniffer\Util\MessageCollector $collector The error cache object. + * @param array $messages The error messages to add to the cache. + * Key is the message, value is the error level. + * + * @return void + */ + private function createErrorCache(MessageCollector $collector, $messages) + { + foreach ($messages as $msg => $type) { + $collector->add($msg, $type); + } + + }//end createErrorCache() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php new file mode 100644 index 000000000..93b3d05e1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php @@ -0,0 +1,114 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Timing; + +use PHP_CodeSniffer\Util\Timing; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Timing::getHumanReadableDuration() method. + * + * @covers \PHP_CodeSniffer\Util\Timing::getHumanReadableDuration + */ +final class GetHumanReadableDurationTest extends TestCase +{ + + + /** + * Test the method. + * + * @param int|float $duration A duration in milliseconds. + * @param string $expected The expected human readable string. + * + * @dataProvider dataGetHumanReadableDuration + * + * @return void + */ + public function testGetHumanReadableDuration($duration, $expected) + { + $this->assertSame($expected, Timing::getHumanReadableDuration($duration)); + + }//end testGetHumanReadableDuration() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataGetHumanReadableDuration() + { + return [ + 'Duration: 0' => [ + 'duration' => 0, + 'expected' => '0ms', + ], + 'Duration: 13 milliseconds' => [ + 'duration' => 13.232101565, + 'expected' => '13ms', + ], + 'Duration: 14 milliseconds' => [ + 'duration' => 13.916015625, + 'expected' => '14ms', + ], + 'Duration: 999 milliseconds' => [ + 'duration' => 999.2236, + 'expected' => '999ms', + ], + 'Duration: 999+ milliseconds' => [ + 'duration' => 999.89236, + 'expected' => '1000ms', + ], + 'Duration: 1 second' => [ + 'duration' => 1000, + 'expected' => '1 secs', + ], + 'Duration: slightly more than 1 second' => [ + 'duration' => 1001.178215, + 'expected' => '1 secs', + ], + 'Duration: just under a 1 minute' => [ + 'duration' => 59999.3851, + 'expected' => '60 secs', + ], + 'Duration: exactly 1 minute' => [ + 'duration' => 60000, + 'expected' => '1 mins', + ], + 'Duration: slightly more than 1 minute' => [ + 'duration' => 60001.7581235, + 'expected' => '1 mins', + ], + 'Duration: 1 minute, just under half a second' => [ + 'duration' => 60499.83639, + 'expected' => '1 mins, 0.5 secs', + ], + 'Duration: 1 minute, just over half a second' => [ + 'duration' => 60501.961238, + 'expected' => '1 mins, 0.5 secs', + ], + 'Duration: 1 minute, 1 second' => [ + 'duration' => 61000, + 'expected' => '1 mins, 1 secs', + ], + 'Duration: exactly 1 hour' => [ + 'duration' => 3600000, + 'expected' => '60 mins', + ], + 'Duration: 89.4 mins' => [ + 'duration' => 5364000, + 'expected' => '89 mins, 24 secs', + ], + ]; + + }//end dataGetHumanReadableDuration() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php new file mode 100644 index 000000000..f5ef11564 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php @@ -0,0 +1,123 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Timing; + +use PHP_CodeSniffer\Util\Timing; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Timing class. + * + * {@internal These tests need to run in separate processes as the Timing class uses static properties + * to keep track of the start time and whether or not the runtime has been printed and these + * can't be unset/reset once set.} + * + * @covers \PHP_CodeSniffer\Util\Timing + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ +final class TimingTest extends TestCase +{ + + + /** + * Verify that getDuration() returns 0 when the timer wasn't started. + * + * @return void + */ + public function testGetDurationWithoutStartReturnsZero() + { + $this->assertSame(0, Timing::getDuration()); + + }//end testGetDurationWithoutStartReturnsZero() + + + /** + * Verify that getDuration() returns the time in milliseconds. + * + * @return void + */ + public function testGetDurationWithStartReturnsMilliseconds() + { + Timing::startTiming(); + usleep(1500); + $duration = Timing::getDuration(); + + $this->assertTrue(is_float($duration)); + $this->assertGreaterThan(1, $duration); + $this->assertLessThan(15, $duration); + + }//end testGetDurationWithStartReturnsMilliseconds() + + + /** + * Verify that printRunTime() doesn't print anything if the timer wasn't started. + * + * @return void + */ + public function testTimeIsNotPrintedIfTimerWasNeverStarted() + { + $this->expectOutputString(''); + Timing::printRunTime(); + + }//end testTimeIsNotPrintedIfTimerWasNeverStarted() + + + /** + * Verify that printRunTime() doesn't print anything if the timer wasn't started. + * + * @return void + */ + public function testTimeIsNotPrintedIfTimerWasNeverStartedEvenWhenForced() + { + $this->expectOutputString(''); + Timing::printRunTime(true); + + }//end testTimeIsNotPrintedIfTimerWasNeverStartedEvenWhenForced() + + + /** + * Verify that printRunTime() when called multiple times only prints the runtime information once. + * + * @return void + */ + public function testTimeIsPrintedOnlyOnce() + { + $this->expectOutputRegex('`^Time: [0-9]+ms; Memory: [0-9\.]+MB'.PHP_EOL.PHP_EOL.'$`'); + + Timing::startTiming(); + usleep(2000); + Timing::printRunTime(); + Timing::printRunTime(); + Timing::printRunTime(); + + }//end testTimeIsPrintedOnlyOnce() + + + /** + * Verify that printRunTime() when called multiple times prints the runtime information multiple times if forced. + * + * @return void + */ + public function testTimeIsPrintedMultipleTimesOnlyIfForced() + { + $this->expectOutputRegex('`^(Time: [0-9]+ms; Memory: [0-9\.]+MB'.PHP_EOL.PHP_EOL.'){3}$`'); + + Timing::startTiming(); + usleep(2000); + Timing::printRunTime(true); + Timing::printRunTime(true); + Timing::printRunTime(true); + + }//end testTimeIsPrintedMultipleTimesOnlyIfForced() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php new file mode 100644 index 000000000..e0bd014c9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php @@ -0,0 +1,162 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Tokens; + +use PHP_CodeSniffer\Util\Tokens; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Tokens::getHighestWeightedToken() method. + * + * @covers \PHP_CodeSniffer\Util\Tokens::getHighestWeightedToken + */ +final class GetHighestWeightedTokenTest extends TestCase +{ + + + /** + * Test the method. + * + * @param array $tokens The tokens to find the heighest weighted one. + * @param int|false $expected The expected function return value. + * + * @dataProvider dataGetHighestWeightedToken + * + * @return void + */ + public function testGetHighestWeightedToken($tokens, $expected) + { + $this->assertSame($expected, Tokens::getHighestWeightedToken($tokens)); + + }//end testGetHighestWeightedToken() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataGetHighestWeightedToken() + { + $data = [ + 'Array of non-tokens passed, returns first' => [ + 'tokens' => [ + PHP_SAPI, + PHP_MAJOR_VERSION, + PHP_OS, + ], + 'expected' => PHP_SAPI, + ], + 'No weightings available for any of the selected tokens, first one wins' => [ + 'tokens' => [ + T_VARIABLE, + T_STRING, + T_EXTENDS, + T_IMPLEMENTS, + ], + 'expected' => T_VARIABLE, + ], + 'single token always returns that token' => [ + 'tokens' => [T_VARIABLE], + 'expected' => T_VARIABLE, + ], + 'Unknown and known token, known token wins' => [ + 'tokens' => [ + T_VARIABLE, + T_SELF, + ], + 'expected' => T_SELF, + ], + 'Known and unknown token, known token wins' => [ + 'tokens' => [ + T_CLOSURE, + T_STRING, + ], + 'expected' => T_CLOSURE, + ], + 'Two tokens with equal weights passed, first one wins' => [ + 'tokens' => [ + T_CLOSURE, + T_FUNCTION, + ], + 'expected' => T_CLOSURE, + ], + 'Five tokens with equal weights passed, first one wins' => [ + 'tokens' => [ + T_NAMESPACE, + T_TRAIT, + T_ENUM, + T_CLASS, + T_INTERFACE, + ], + 'expected' => T_NAMESPACE, + ], + 'Tokens with different weights passed, heightest (25) wins' => [ + 'tokens' => [ + T_BITWISE_OR, + T_SELF, + T_MUL_EQUAL, + ], + 'expected' => T_SELF, + ], + 'Tokens with different weights passed, heightest (50) wins' => [ + 'tokens' => [ + T_BITWISE_XOR, + T_CATCH, + T_SPACESHIP, + T_PARENT, + ], + 'expected' => T_CATCH, + ], + ]; + + $high100 = [ + T_MULTIPLY, + T_BITWISE_AND, + T_SELF, + T_FOREACH, + T_CLOSURE, + ]; + $data['Tokens with different weights passed, ordered low-high, heightest (100) wins'] = [ + 'tokens' => $high100, + 'expected' => T_CLOSURE, + ]; + + shuffle($high100); + $data['Tokens with different weights passed, order random, heightest (100) wins'] = [ + 'tokens' => $high100, + 'expected' => T_CLOSURE, + ]; + + $high1000 = [ + T_ENUM, + T_FUNCTION, + T_ELSEIF, + T_PARENT, + T_BITWISE_OR, + T_MODULUS, + ]; + $data['Tokens with different weights passed, ordered low-high, heightest (1000) wins'] = [ + 'tokens' => $high1000, + 'expected' => T_ENUM, + ]; + + shuffle($high1000); + $data['Tokens with different weights passed, order random, heightest (1000) wins'] = [ + 'tokens' => $high1000, + 'expected' => T_ENUM, + ]; + + return $data; + + }//end dataGetHighestWeightedToken() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php new file mode 100644 index 000000000..28c6c613c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php @@ -0,0 +1,184 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Tokens; + +use PHP_CodeSniffer\Util\Tokens; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Tokens::tokenName() method. + * + * @covers \PHP_CodeSniffer\Util\Tokens::tokenName + */ +final class TokenNameTest extends TestCase +{ + + + /** + * Test the method. + * + * @param int|string $tokenCode The PHP/PHPCS token code to get the name for. + * @param string $expected The expected token name. + * + * @dataProvider dataTokenName + * @dataProvider dataPolyfilledPHPNativeTokens + * + * @return void + */ + public function testTokenName($tokenCode, $expected) + { + $this->assertSame($expected, Tokens::tokenName($tokenCode)); + + }//end testTokenName() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataTokenName() + { + return [ + 'PHP native token: T_ECHO' => [ + 'tokenCode' => T_ECHO, + 'expected' => 'T_ECHO', + ], + 'PHP native token: T_FUNCTION' => [ + 'tokenCode' => T_FUNCTION, + 'expected' => 'T_FUNCTION', + ], + 'PHPCS native token: T_CLOSURE' => [ + 'tokenCode' => T_CLOSURE, + 'expected' => 'T_CLOSURE', + ], + 'PHPCS native token: T_STRING_CONCAT' => [ + 'tokenCode' => T_STRING_CONCAT, + 'expected' => 'T_STRING_CONCAT', + ], + + // Document the current behaviour for invalid input. + // This behaviour is subject to change. + 'Non-token integer passed' => [ + 'tokenCode' => 100000, + 'expected' => 'UNKNOWN', + ], + 'Non-token string passed' => [ + 'tokenCode' => 'something', + 'expected' => 'ing', + ], + ]; + + }//end dataTokenName() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataPolyfilledPHPNativeTokens() + { + return [ + 'PHP 5.5 native token, polyfilled: T_FINALLY' => [ + 'tokenCode' => T_FINALLY, + 'expected' => 'T_FINALLY', + ], + 'PHP 5.5 native token, polyfilled: T_YIELD' => [ + 'tokenCode' => T_YIELD, + 'expected' => 'T_YIELD', + ], + + 'PHP 5.6 native token, polyfilled: T_ELLIPSIS' => [ + 'tokenCode' => T_ELLIPSIS, + 'expected' => 'T_ELLIPSIS', + ], + 'PHP 5.6 native token, polyfilled: T_POW' => [ + 'tokenCode' => T_POW, + 'expected' => 'T_POW', + ], + 'PHP 5.6 native token, polyfilled: T_POW_EQUAL' => [ + 'tokenCode' => T_POW_EQUAL, + 'expected' => 'T_POW_EQUAL', + ], + + 'PHP 7.0 native token, polyfilled: T_SPACESHIP' => [ + 'tokenCode' => T_SPACESHIP, + 'expected' => 'T_SPACESHIP', + ], + 'PHP 7.0 native token, polyfilled: T_COALESCE' => [ + 'tokenCode' => T_COALESCE, + 'expected' => 'T_COALESCE', + ], + 'PHP 7.0 native token, polyfilled: T_YIELD_FROM' => [ + 'tokenCode' => T_YIELD_FROM, + 'expected' => 'T_YIELD_FROM', + ], + + 'PHP 7.4 native token, polyfilled: T_COALESCE_EQUAL' => [ + 'tokenCode' => T_COALESCE_EQUAL, + 'expected' => 'T_COALESCE_EQUAL', + ], + 'PHP 7.4 native token, polyfilled: T_BAD_CHARACTER' => [ + 'tokenCode' => T_BAD_CHARACTER, + 'expected' => 'T_BAD_CHARACTER', + ], + 'PHP 7.4 native token, polyfilled: T_FN' => [ + 'tokenCode' => T_FN, + 'expected' => 'T_FN', + ], + + 'PHP 8.0 native token, polyfilled: T_NULLSAFE_OBJECT_OPERATOR' => [ + 'tokenCode' => T_NULLSAFE_OBJECT_OPERATOR, + 'expected' => 'T_NULLSAFE_OBJECT_OPERATOR', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_QUALIFIED' => [ + 'tokenCode' => T_NAME_QUALIFIED, + 'expected' => 'T_NAME_QUALIFIED', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_FULLY_QUALIFIED' => [ + 'tokenCode' => T_NAME_FULLY_QUALIFIED, + 'expected' => 'T_NAME_FULLY_QUALIFIED', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_RELATIVE' => [ + 'tokenCode' => T_NAME_RELATIVE, + 'expected' => 'T_NAME_RELATIVE', + ], + 'PHP 8.0 native token, polyfilled: T_MATCH' => [ + 'tokenCode' => T_MATCH, + 'expected' => 'T_MATCH', + ], + 'PHP 8.0 native token, polyfilled: T_ATTRIBUTE' => [ + 'tokenCode' => T_ATTRIBUTE, + 'expected' => 'T_ATTRIBUTE', + ], + + 'PHP 8.1 native token, polyfilled: T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG' => [ + 'tokenCode' => T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + 'expected' => 'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG', + ], + 'PHP 8.1 native token, polyfilled: T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG' => [ + 'tokenCode' => T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, + 'expected' => 'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', + ], + 'PHP 8.1 native token, polyfilled: T_READONLY' => [ + 'tokenCode' => T_READONLY, + 'expected' => 'T_READONLY', + ], + 'PHP 8.1 native token, polyfilled: T_ENUM' => [ + 'tokenCode' => T_ENUM, + 'expected' => 'T_ENUM', + ], + ]; + + }//end dataPolyfilledPHPNativeTokens() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/FileList.php b/app/vendor/squizlabs/php_codesniffer/tests/FileList.php index 8ef57b7af..ac3c944f3 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/FileList.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/FileList.php @@ -4,11 +4,15 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use RegexIterator; + class FileList { @@ -52,21 +56,21 @@ public function __construct($directory, $rootPath='', $filter='') { $this->rootPath = $rootPath; - $directory = new \RecursiveDirectoryIterator( + $directory = new RecursiveDirectoryIterator( $directory, - \RecursiveDirectoryIterator::UNIX_PATHS + RecursiveDirectoryIterator::UNIX_PATHS ); - $flattened = new \RecursiveIteratorIterator( + $flattened = new RecursiveIteratorIterator( $directory, - \RecursiveIteratorIterator::LEAVES_ONLY, - \RecursiveIteratorIterator::CATCH_GET_CHILD + RecursiveIteratorIterator::LEAVES_ONLY, + RecursiveIteratorIterator::CATCH_GET_CHILD ); if ($filter === '') { $filter = sprintf($this->baseRegex, preg_quote($this->rootPath)); } - $this->fileIterator = new \RegexIterator($flattened, $filter); + $this->fileIterator = new RegexIterator($flattened, $filter); return $this; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php index c050a0c2a..ccd90c513 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php @@ -8,15 +8,16 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Standards; -use PHP_CodeSniffer\Config; +use DirectoryIterator; use PHP_CodeSniffer\Exceptions\RuntimeException; -use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHP_CodeSniffer\Util\Common; use PHPUnit\Framework\TestCase; @@ -50,15 +51,17 @@ abstract class AbstractSniffUnitTest extends TestCase /** * Sets up this unit test. * + * @before + * * @return void */ - protected function setUp() + protected function setUpPrerequisites() { $class = get_class($this); $this->standardsDir = $GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'][$class]; $this->testsDir = $GLOBALS['PHP_CODESNIFFER_TEST_DIRS'][$class]; - }//end setUp() + }//end setUpPrerequisites() /** @@ -76,7 +79,7 @@ protected function getTestFiles($testFileBase) $testFiles = []; $dir = substr($testFileBase, 0, strrpos($testFileBase, DIRECTORY_SEPARATOR)); - $di = new \DirectoryIterator($dir); + $di = new DirectoryIterator($dir); foreach ($di as $file) { $path = $file->getPathname(); @@ -88,7 +91,7 @@ protected function getTestFiles($testFileBase) } // Put them in order. - sort($testFiles); + sort($testFiles, SORT_NATURAL); return $testFiles; @@ -132,7 +135,7 @@ final public function testSniff() if (isset($GLOBALS['PHP_CODESNIFFER_CONFIG']) === true) { $config = $GLOBALS['PHP_CODESNIFFER_CONFIG']; } else { - $config = new Config(); + $config = new ConfigDouble(); $config->cache = false; $GLOBALS['PHP_CODESNIFFER_CONFIG'] = $config; } @@ -188,15 +191,20 @@ final public function testSniff() // Check for a .fixed file to check for accuracy of fixes. $fixedFile = $testFile.'.fixed'; + $filename = basename($testFile); if (file_exists($fixedFile) === true) { - $diff = $phpcsFile->fixer->generateDiff($fixedFile); - if (trim($diff) !== '') { - $filename = basename($testFile); - $fixedFilename = basename($fixedFile); - $failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff"; + if ($phpcsFile->fixer->getContents() !== file_get_contents($fixedFile)) { + // Only generate the (expensive) diff if a difference is expected. + $diff = $phpcsFile->fixer->generateDiff($fixedFile); + if (trim($diff) !== '') { + $fixedFilename = basename($fixedFile); + $failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff"; + } } + } else if (is_callable([$this, 'addWarning']) === true) { + $this->addWarning("Missing fixed version of $filename to verify the accuracy of fixes, while the sniff is making fixes against the test case file"); } - } + }//end if // Restore the config. $config->setSettings($oldConfig); @@ -431,7 +439,6 @@ public function generateFailureMessages(LocalFile $file) */ public function setCliValues($filename, $config) { - return; }//end setCliValues() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php index 24527dd51..1e273e28e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php @@ -4,15 +4,17 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Standards; -use PHP_CodeSniffer\Util\Standards; use PHP_CodeSniffer\Autoload; -use PHPUnit\TextUI\TestRunner; +use PHP_CodeSniffer\Util\Standards; use PHPUnit\Framework\TestSuite; +use PHPUnit\TextUI\TestRunner; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; class AllSniffs { @@ -46,8 +48,6 @@ public static function suite() $suite = new TestSuite('PHP CodeSniffer Standards'); - $isInstalled = !is_file(__DIR__.'/../../autoload.php'); - // Optionally allow for ignoring the tests for one or more standards. $ignoreTestsForStandards = getenv('PHPCS_IGNORE_TESTS'); if ($ignoreTestsForStandards === false) { @@ -61,26 +61,17 @@ public static function suite() foreach ($installedStandards as $standard => $details) { Autoload::addSearchPath($details['path'], $details['namespace']); - // If the test is running PEAR installed, the built-in standards - // are split into different directories; one for the sniffs and - // a different file system location for tests. - if ($isInstalled === true && is_dir(dirname($details['path']).DIRECTORY_SEPARATOR.'Generic') === true) { - $testPath = realpath(__DIR__.'/../../src/Standards/'.$standard); - } else { - $testPath = $details['path']; - } - if (in_array($standard, $ignoreTestsForStandards, true) === true) { continue; } - $testsDir = $testPath.DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR; + $testsDir = $details['path'].DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR; if (is_dir($testsDir) === false) { // No tests for this standard. continue; } - $di = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($testsDir)); + $di = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($testsDir)); foreach ($di as $file) { // Skip hidden files. diff --git a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php index 9eb269f8b..4598a8562 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php @@ -4,13 +4,13 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; -use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; use PHPUnit\Framework\TestResult; +use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; class TestSuite extends PHPUnit_TestSuite { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php index 43db293d5..ad0947c58 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php @@ -4,13 +4,13 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; -use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; use PHPUnit\Framework\TestResult; +use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; class TestSuite extends PHPUnit_TestSuite { @@ -19,11 +19,11 @@ class TestSuite extends PHPUnit_TestSuite /** * Runs the tests and collects their result in a TestResult. * - * @param \PHPUnit\Framework\TestResult $result A test result. + * @param \PHPUnit\Framework\TestResult|null $result A test result. * * @return \PHPUnit\Framework\TestResult */ - public function run(TestResult $result=null): TestResult + public function run(?TestResult $result=null): TestResult { $result = parent::run($result); printPHPCodeSnifferTestOutput(); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php b/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php index 47084d113..e8ebdbbdd 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php @@ -4,26 +4,41 @@ * * @author Greg Sherwood * @copyright 2006-2017 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ if (defined('PHP_CODESNIFFER_IN_TESTS') === false) { define('PHP_CODESNIFFER_IN_TESTS', true); } +/* + * Determine whether the test suite should be run in CBF mode. + * + * Use `` in a `phpunit.xml` file + * or set the ENV variable at an OS-level to enable CBF mode. + * + * To run the CBF specific tests, use the following command: + * vendor/bin/phpunit --group CBF --exclude-group nothing + * + * If the ENV variable has not been set, or is set to "false", the tests will run in CS mode. + */ + if (defined('PHP_CODESNIFFER_CBF') === false) { - define('PHP_CODESNIFFER_CBF', false); + $cbfMode = getenv('PHP_CODESNIFFER_CBF'); + if ($cbfMode === '1') { + define('PHP_CODESNIFFER_CBF', true); + echo 'Note: Tests are running in "CBF" mode'.PHP_EOL.PHP_EOL; + } else { + define('PHP_CODESNIFFER_CBF', false); + echo 'Note: Tests are running in "CS" mode'.PHP_EOL.PHP_EOL; + } } if (defined('PHP_CODESNIFFER_VERBOSITY') === false) { define('PHP_CODESNIFFER_VERBOSITY', 0); } -if (is_file(__DIR__.'/../autoload.php') === true) { - include_once __DIR__.'/../autoload.php'; -} else { - include_once 'PHP/CodeSniffer/autoload.php'; -} +require_once __DIR__.'/../autoload.php'; $tokens = new \PHP_CodeSniffer\Util\Tokens(); @@ -44,13 +59,6 @@ class_alias('PHPUnit_TextUI_TestRunner', 'PHPUnit'.'\TextUI\TestRunner'); class_alias('PHPUnit_Framework_TestResult', 'PHPUnit'.'\Framework\TestResult'); } -// Determine whether this is a PEAR install or not. -$GLOBALS['PHP_CODESNIFFER_PEAR'] = false; - -if (is_file(__DIR__.'/../autoload.php') === false) { - $GLOBALS['PHP_CODESNIFFER_PEAR'] = true; -} - /** * A global util function to help print unit test fixing data. diff --git a/app/vendor/symfony/config/Builder/ClassBuilder.php b/app/vendor/symfony/config/Builder/ClassBuilder.php index 8194a1526..619ebd857 100644 --- a/app/vendor/symfony/config/Builder/ClassBuilder.php +++ b/app/vendor/symfony/config/Builder/ClassBuilder.php @@ -119,7 +119,7 @@ public function addMethod(string $name, string $body, array $params = []): void $this->methods[] = new Method(strtr($body, ['NAME' => $this->camelCase($name)] + $params)); } - public function addProperty(string $name, string $classType = null, string $defaultValue = null): Property + public function addProperty(string $name, ?string $classType = null, ?string $defaultValue = null): Property { $property = new Property($name, '_' !== $name[0] ? $this->camelCase($name) : $name); if (null !== $classType) { diff --git a/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php b/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php index 2f00a99be..d43d814eb 100644 --- a/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php +++ b/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php @@ -478,8 +478,8 @@ private function buildToArray(ClassBuilder $class): void if (null !== $p->getType()) { if ($p->isArray()) { $code = $p->areScalarsAllowed() - ? 'array_map(function ($v) { return $v instanceof CLASS ? $v->toArray() : $v; }, $this->PROPERTY)' - : 'array_map(function ($v) { return $v->toArray(); }, $this->PROPERTY)' + ? 'array_map(fn ($v) => $v instanceof CLASS ? $v->toArray() : $v, $this->PROPERTY)' + : 'array_map(fn ($v) => $v->toArray(), $this->PROPERTY)' ; } else { $code = $p->areScalarsAllowed() @@ -514,8 +514,8 @@ private function buildConstructor(ClassBuilder $class): void if (null !== $p->getType()) { if ($p->isArray()) { $code = $p->areScalarsAllowed() - ? 'array_map(function ($v) { return \is_array($v) ? new '.$p->getType().'($v) : $v; }, $value[\'ORG_NAME\'])' - : 'array_map(function ($v) { return new '.$p->getType().'($v); }, $value[\'ORG_NAME\'])' + ? 'array_map(fn ($v) => \is_array($v) ? new '.$p->getType().'($v) : $v, $value[\'ORG_NAME\'])' + : 'array_map(fn ($v) => new '.$p->getType().'($v), $value[\'ORG_NAME\'])' ; } else { $code = $p->areScalarsAllowed() @@ -589,7 +589,6 @@ private function hasNormalizationClosures(NodeInterface $node): bool } catch (\ReflectionException) { return false; } - $r->setAccessible(true); return [] !== $r->getValue($node); } diff --git a/app/vendor/symfony/config/ConfigCacheInterface.php b/app/vendor/symfony/config/ConfigCacheInterface.php index be7f0986c..f8d270634 100644 --- a/app/vendor/symfony/config/ConfigCacheInterface.php +++ b/app/vendor/symfony/config/ConfigCacheInterface.php @@ -43,5 +43,5 @@ public function isFresh(): bool; * * @throws \RuntimeException When the cache file cannot be written */ - public function write(string $content, array $metadata = null); + public function write(string $content, ?array $metadata = null); } diff --git a/app/vendor/symfony/config/Definition/BaseNode.php b/app/vendor/symfony/config/Definition/BaseNode.php index 85f0f7eeb..6e2a19227 100644 --- a/app/vendor/symfony/config/Definition/BaseNode.php +++ b/app/vendor/symfony/config/Definition/BaseNode.php @@ -46,7 +46,7 @@ abstract class BaseNode implements NodeInterface /** * @throws \InvalidArgumentException if the name contains a period */ - public function __construct(?string $name, NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR) + public function __construct(?string $name, ?NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR) { if (str_contains($name = (string) $name, $pathSeparator)) { throw new \InvalidArgumentException('The name must not contain ".'.$pathSeparator.'".'); diff --git a/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php index 0110f0502..7a82334ee 100644 --- a/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php @@ -37,7 +37,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition protected $nodeBuilder; protected $normalizeKeys = true; - public function __construct(?string $name, NodeParentInterface $parent = null) + public function __construct(?string $name, ?NodeParentInterface $parent = null) { parent::__construct($name, $parent); @@ -126,7 +126,7 @@ public function addDefaultsIfNotSet(): static * * @return $this */ - public function addDefaultChildrenIfNoneSet(int|string|array $children = null): static + public function addDefaultChildrenIfNoneSet(int|string|array|null $children = null): static { $this->addDefaultChildren = $children; @@ -169,7 +169,7 @@ public function disallowNewKeysInSubsequentConfigs(): static * * @return $this */ - public function fixXmlConfig(string $singular, string $plural = null): static + public function fixXmlConfig(string $singular, ?string $plural = null): static { $this->normalization()->remap($singular, $plural); @@ -348,7 +348,7 @@ protected function getNodeBuilder(): NodeBuilder protected function createNode(): NodeInterface { - if (null === $this->prototype) { + if (!isset($this->prototype)) { $node = new ArrayNode($this->name, $this->parent, $this->pathSeparator); $this->validateConcreteNode($node); @@ -382,7 +382,7 @@ protected function createNode(): NodeInterface if (false !== $this->addDefaultChildren) { $node->setAddChildrenIfNoneSet($this->addDefaultChildren); - if ($this->prototype instanceof static && null === $this->prototype->prototype) { + if ($this->prototype instanceof static && !isset($this->prototype->prototype)) { $this->prototype->addDefaultsIfNotSet(); } } @@ -404,18 +404,18 @@ protected function createNode(): NodeInterface $node->setDeprecated($this->deprecation['package'], $this->deprecation['version'], $this->deprecation['message']); } - if (null !== $this->normalization) { + if (isset($this->normalization)) { $node->setNormalizationClosures($this->normalization->before); $node->setNormalizedTypes($this->normalization->declaredTypes); $node->setXmlRemappings($this->normalization->remappings); } - if (null !== $this->merge) { + if (isset($this->merge)) { $node->setAllowOverwrite($this->merge->allowOverwrite); $node->setAllowFalse($this->merge->allowFalse); } - if (null !== $this->validation) { + if (isset($this->validation)) { $node->setFinalValidationClosures($this->validation->rules); } diff --git a/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php index 3d8fad4d5..15e63961a 100644 --- a/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php @@ -21,7 +21,7 @@ */ class BooleanNodeDefinition extends ScalarNodeDefinition { - public function __construct(?string $name, NodeParentInterface $parent = null) + public function __construct(?string $name, ?NodeParentInterface $parent = null) { parent::__construct($name, $parent); diff --git a/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php b/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php index 9cb441481..93cdb49dd 100644 --- a/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php @@ -42,7 +42,7 @@ public function __construct(NodeDefinition $node) * * @return $this */ - public function always(\Closure $then = null): static + public function always(?\Closure $then = null): static { $this->ifPart = static fn () => true; $this->allowedTypes = self::TYPE_ANY; @@ -61,7 +61,7 @@ public function always(\Closure $then = null): static * * @return $this */ - public function ifTrue(\Closure $closure = null): static + public function ifTrue(?\Closure $closure = null): static { $this->ifPart = $closure ?? static fn ($v) => true === $v; $this->allowedTypes = self::TYPE_ANY; diff --git a/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php b/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php index 7cda0bc7d..93069d437 100644 --- a/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php @@ -39,7 +39,7 @@ public function __construct() * * @return $this */ - public function setParent(ParentNodeDefinitionInterface $parent = null): static + public function setParent(?ParentNodeDefinitionInterface $parent = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/form', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php index 1cd32ca3e..cf2173e17 100644 --- a/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php @@ -38,7 +38,7 @@ abstract class NodeDefinition implements NodeParentInterface protected $parent; protected $attributes = []; - public function __construct(?string $name, NodeParentInterface $parent = null) + public function __construct(?string $name, ?NodeParentInterface $parent = null) { $this->parent = $parent; $this->name = $name; @@ -91,7 +91,7 @@ public function attribute(string $key, mixed $value): static /** * Returns the parent node. */ - public function end(): NodeParentInterface|NodeBuilder|NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition|null + public function end(): NodeParentInterface|NodeBuilder|self|ArrayNodeDefinition|VariableNodeDefinition|null { return $this->parent; } @@ -105,7 +105,7 @@ public function getNode(bool $forceRootNode = false): NodeInterface $this->parent = null; } - if (null !== $this->normalization) { + if (isset($this->normalization)) { $allowedTypes = []; foreach ($this->normalization->before as $expr) { $allowedTypes[] = $expr->allowedTypes; @@ -115,7 +115,7 @@ public function getNode(bool $forceRootNode = false): NodeInterface $this->normalization->declaredTypes = $allowedTypes; } - if (null !== $this->validation) { + if (isset($this->validation)) { $this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules); } diff --git a/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php b/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php index 0e362d9fa..1f6b34441 100644 --- a/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php @@ -36,7 +36,7 @@ public function __construct(NodeDefinition $node) * * @return $this */ - public function remap(string $key, string $plural = null): static + public function remap(string $key, ?string $plural = null): static { $this->remappings[] = [$key, null === $plural ? $key.'s' : $plural]; @@ -48,7 +48,7 @@ public function remap(string $key, string $plural = null): static * * @return ExprBuilder|$this */ - public function before(\Closure $closure = null): ExprBuilder|static + public function before(?\Closure $closure = null): ExprBuilder|static { if (null !== $closure) { $this->before[] = $closure; diff --git a/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php b/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php index 4f868f703..f7da3e794 100644 --- a/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php @@ -20,10 +20,17 @@ */ class TreeBuilder implements NodeParentInterface { + /** + * @var NodeInterface|null + */ protected $tree; + + /** + * @var NodeDefinition + */ protected $root; - public function __construct(string $name, string $type = 'array', NodeBuilder $builder = null) + public function __construct(string $name, string $type = 'array', ?NodeBuilder $builder = null) { $builder ??= new NodeBuilder(); $this->root = $builder->node($name, $type)->setParent($this); @@ -44,11 +51,7 @@ public function getRootNode(): NodeDefinition|ArrayNodeDefinition */ public function buildTree(): NodeInterface { - if (null !== $this->tree) { - return $this->tree; - } - - return $this->tree = $this->root->getNode(true); + return $this->tree ??= $this->root->getNode(true); } /** diff --git a/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php b/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php index 1bee851b6..64623d6d6 100644 --- a/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php @@ -31,7 +31,7 @@ public function __construct(NodeDefinition $node) * * @return ExprBuilder|$this */ - public function rule(\Closure $closure = null): ExprBuilder|static + public function rule(?\Closure $closure = null): ExprBuilder|static { if (null !== $closure) { $this->rules[] = $closure; diff --git a/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php index c49391f44..a4cc53a55 100644 --- a/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php @@ -33,11 +33,11 @@ protected function createNode(): NodeInterface { $node = $this->instantiateNode(); - if (null !== $this->normalization) { + if (isset($this->normalization)) { $node->setNormalizationClosures($this->normalization->before); } - if (null !== $this->merge) { + if (isset($this->merge)) { $node->setAllowOverwrite($this->merge->allowOverwrite); } @@ -55,7 +55,7 @@ protected function createNode(): NodeInterface $node->setDeprecated($this->deprecation['package'], $this->deprecation['version'], $this->deprecation['message']); } - if (null !== $this->validation) { + if (isset($this->validation)) { $node->setFinalValidationClosures($this->validation->rules); } diff --git a/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php b/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php index 006a444be..13fe45ca4 100644 --- a/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php +++ b/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php @@ -29,7 +29,7 @@ public function __construct( ) { } - public function import(string $resource, string $type = null, bool $ignoreErrors = false): void + public function import(string $resource, ?string $type = null, bool $ignoreErrors = false): void { $this->loader->setCurrentDir(\dirname($this->path)); $this->loader->import($resource, $type, $ignoreErrors, $this->file); diff --git a/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php b/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php index 34f93ce07..aac2d8456 100644 --- a/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php +++ b/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php @@ -34,7 +34,7 @@ class XmlReferenceDumper /** * @return string */ - public function dump(ConfigurationInterface $configuration, string $namespace = null) + public function dump(ConfigurationInterface $configuration, ?string $namespace = null) { return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace); } @@ -42,7 +42,7 @@ public function dump(ConfigurationInterface $configuration, string $namespace = /** * @return string */ - public function dumpNode(NodeInterface $node, string $namespace = null) + public function dumpNode(NodeInterface $node, ?string $namespace = null) { $this->reference = ''; $this->writeNode($node, 0, true, $namespace); @@ -52,7 +52,7 @@ public function dumpNode(NodeInterface $node, string $namespace = null) return $ref; } - private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, string $namespace = null): void + private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, ?string $namespace = null): void { $rootName = ($root ? 'config' : $node->getName()); $rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null)); diff --git a/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php b/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php index 97a391ada..abcf1bd9e 100644 --- a/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php +++ b/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php @@ -18,7 +18,6 @@ use Symfony\Component\Config\Definition\NodeInterface; use Symfony\Component\Config\Definition\PrototypedArrayNode; use Symfony\Component\Config\Definition\ScalarNode; -use Symfony\Component\Config\Definition\VariableNode; use Symfony\Component\Yaml\Inline; /** @@ -80,7 +79,7 @@ public function dumpNode(NodeInterface $node) return $ref; } - private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void + private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void { $comments = []; $default = ''; @@ -99,19 +98,12 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null $children = $this->getPrototypeChildren($node); } - if (!$children) { - if ($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue())) { - $default = ''; - } elseif (!\is_array($example)) { - $default = '[]'; - } + if (!$children && !($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue()))) { + $default = '[]'; } } elseif ($node instanceof EnumNode) { $comments[] = 'One of '.$node->getPermissibleValues('; '); $default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~'; - } elseif (VariableNode::class === $node::class && \is_array($example)) { - // If there is an array example, we are sure we dont need to print a default value - $default = ''; } else { $default = '~'; @@ -179,7 +171,7 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null $this->writeLine('# '.$message.':', $depth * 4 + 4); - $this->writeArray(array_map(Inline::dump(...), $example), $depth + 1); + $this->writeArray(array_map(Inline::dump(...), $example), $depth + 1, true); } if ($children) { @@ -200,7 +192,7 @@ private function writeLine(string $text, int $indent = 0): void $this->reference .= sprintf($format, $text)."\n"; } - private function writeArray(array $array, int $depth): void + private function writeArray(array $array, int $depth, bool $asComment = false): void { $isIndexed = array_is_list($array); @@ -211,14 +203,16 @@ private function writeArray(array $array, int $depth): void $val = $value; } + $prefix = $asComment ? '# ' : ''; + if ($isIndexed) { - $this->writeLine('- '.$val, $depth * 4); + $this->writeLine($prefix.'- '.$val, $depth * 4); } else { - $this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4); + $this->writeLine(sprintf('%s%-20s %s', $prefix, $key.':', $val), $depth * 4); } if (\is_array($value)) { - $this->writeArray($value, $depth + 1); + $this->writeArray($value, $depth + 1, $asComment); } } } diff --git a/app/vendor/symfony/config/Definition/EnumNode.php b/app/vendor/symfony/config/Definition/EnumNode.php index 4edeae904..f5acbe906 100644 --- a/app/vendor/symfony/config/Definition/EnumNode.php +++ b/app/vendor/symfony/config/Definition/EnumNode.php @@ -22,7 +22,7 @@ class EnumNode extends ScalarNode { private array $values; - public function __construct(?string $name, NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) + public function __construct(?string $name, ?NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) { if (!$values) { throw new \InvalidArgumentException('$values must contain at least one element.'); diff --git a/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php b/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php index 506f787ca..940b894f7 100644 --- a/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php +++ b/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php @@ -34,7 +34,7 @@ public function __construct( parent::__construct($locator); } - public function load(mixed $resource, string $type = null): mixed + public function load(mixed $resource, ?string $type = null): mixed { // the loader variable is exposed to the included file below $loader = $this; @@ -57,7 +57,7 @@ public function load(mixed $resource, string $type = null): mixed return null; } - public function supports(mixed $resource, string $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { if (!\is_string($resource)) { return false; diff --git a/app/vendor/symfony/config/Definition/NumericNode.php b/app/vendor/symfony/config/Definition/NumericNode.php index da32b843a..22359fd25 100644 --- a/app/vendor/symfony/config/Definition/NumericNode.php +++ b/app/vendor/symfony/config/Definition/NumericNode.php @@ -23,7 +23,7 @@ class NumericNode extends ScalarNode protected $min; protected $max; - public function __construct(?string $name, NodeInterface $parent = null, int|float $min = null, int|float $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) + public function __construct(?string $name, ?NodeInterface $parent = null, int|float|null $min = null, int|float|null $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) { parent::__construct($name, $parent, $pathSeparator); $this->min = $min; diff --git a/app/vendor/symfony/config/Definition/Processor.php b/app/vendor/symfony/config/Definition/Processor.php index dc3d4c69b..272ddcc44 100644 --- a/app/vendor/symfony/config/Definition/Processor.php +++ b/app/vendor/symfony/config/Definition/Processor.php @@ -67,7 +67,7 @@ public function processConfiguration(ConfigurationInterface $configuration, arra * @param string $key The key to normalize * @param string|null $plural The plural form of the key if it is irregular */ - public static function normalizeConfig(array $config, string $key, string $plural = null): array + public static function normalizeConfig(array $config, string $key, ?string $plural = null): array { $plural ??= $key.'s'; diff --git a/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php b/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php index da0b55ba8..2d2a4de00 100644 --- a/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php +++ b/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php @@ -18,7 +18,7 @@ */ class FileLoaderImportCircularReferenceException extends LoaderLoadException { - public function __construct(array $resources, int $code = 0, \Throwable $previous = null) + public function __construct(array $resources, int $code = 0, ?\Throwable $previous = null) { $message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]); diff --git a/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php b/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php index c5173ae58..a3fcc901b 100644 --- a/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php +++ b/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php @@ -20,7 +20,7 @@ class FileLocatorFileNotFoundException extends \InvalidArgumentException { private array $paths; - public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, array $paths = []) + public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, array $paths = []) { parent::__construct($message, $code, $previous); diff --git a/app/vendor/symfony/config/Exception/LoaderLoadException.php b/app/vendor/symfony/config/Exception/LoaderLoadException.php index 57afd6a8d..2b40688a5 100644 --- a/app/vendor/symfony/config/Exception/LoaderLoadException.php +++ b/app/vendor/symfony/config/Exception/LoaderLoadException.php @@ -25,7 +25,7 @@ class LoaderLoadException extends \Exception * @param \Throwable|null $previous A previous exception * @param string|null $type The type of resource */ - public function __construct(mixed $resource, string $sourceResource = null, int $code = 0, \Throwable $previous = null, string $type = null) + public function __construct(mixed $resource, ?string $sourceResource = null, int $code = 0, ?\Throwable $previous = null, ?string $type = null) { if (!\is_string($resource)) { try { diff --git a/app/vendor/symfony/config/FileLocator.php b/app/vendor/symfony/config/FileLocator.php index e147d9b1a..7f85367d0 100644 --- a/app/vendor/symfony/config/FileLocator.php +++ b/app/vendor/symfony/config/FileLocator.php @@ -31,9 +31,11 @@ public function __construct(string|array $paths = []) } /** - * @return string|array + * @return string|string[] + * + * @psalm-return ($first is true ? string : string[]) */ - public function locate(string $name, string $currentPath = null, bool $first = true) + public function locate(string $name, ?string $currentPath = null, bool $first = true) { if ('' === $name) { throw new \InvalidArgumentException('An empty file name is not valid to be located.'); @@ -84,7 +86,8 @@ private function isAbsolutePath(string $file): bool && ':' === $file[1] && ('\\' === $file[2] || '/' === $file[2]) ) - || null !== parse_url($file, \PHP_URL_SCHEME) + || parse_url($file, \PHP_URL_SCHEME) + || str_starts_with($file, 'phar:///') // "parse_url()" doesn't handle absolute phar path, despite being valid ) { return true; } diff --git a/app/vendor/symfony/config/FileLocatorInterface.php b/app/vendor/symfony/config/FileLocatorInterface.php index e3ca1d49c..755cf018a 100644 --- a/app/vendor/symfony/config/FileLocatorInterface.php +++ b/app/vendor/symfony/config/FileLocatorInterface.php @@ -25,10 +25,12 @@ interface FileLocatorInterface * @param string|null $currentPath The current path * @param bool $first Whether to return the first occurrence or an array of filenames * - * @return string|array The full path to the file or an array of file paths + * @return string|string[] The full path to the file or an array of file paths * * @throws \InvalidArgumentException If $name is empty * @throws FileLocatorFileNotFoundException If a file is not found + * + * @psalm-return ($first is true ? string : string[]) */ - public function locate(string $name, string $currentPath = null, bool $first = true); + public function locate(string $name, ?string $currentPath = null, bool $first = true); } diff --git a/app/vendor/symfony/config/Loader/DelegatingLoader.php b/app/vendor/symfony/config/Loader/DelegatingLoader.php index fac3724e9..045a559e2 100644 --- a/app/vendor/symfony/config/Loader/DelegatingLoader.php +++ b/app/vendor/symfony/config/Loader/DelegatingLoader.php @@ -28,7 +28,7 @@ public function __construct(LoaderResolverInterface $resolver) $this->resolver = $resolver; } - public function load(mixed $resource, string $type = null): mixed + public function load(mixed $resource, ?string $type = null): mixed { if (false === $loader = $this->resolver->resolve($resource, $type)) { throw new LoaderLoadException($resource, null, 0, null, $type); @@ -37,7 +37,7 @@ public function load(mixed $resource, string $type = null): mixed return $loader->load($resource, $type); } - public function supports(mixed $resource, string $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { return false !== $this->resolver->resolve($resource, $type); } diff --git a/app/vendor/symfony/config/Loader/FileLoader.php b/app/vendor/symfony/config/Loader/FileLoader.php index 8cfaa23ba..8275ffcd3 100644 --- a/app/vendor/symfony/config/Loader/FileLoader.php +++ b/app/vendor/symfony/config/Loader/FileLoader.php @@ -31,7 +31,7 @@ abstract class FileLoader extends Loader private ?string $currentDir = null; - public function __construct(FileLocatorInterface $locator, string $env = null) + public function __construct(FileLocatorInterface $locator, ?string $env = null) { $this->locator = $locator; parent::__construct($env); @@ -70,7 +70,7 @@ public function getLocator(): FileLocatorInterface * @throws FileLoaderImportCircularReferenceException * @throws FileLocatorFileNotFoundException */ - public function import(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null, string|array $exclude = null) + public function import(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null, string|array|null $exclude = null) { if (\is_string($resource) && \strlen($resource) !== ($i = strcspn($resource, '*?{[')) && !str_contains($resource, "\n")) { $excluded = []; @@ -101,7 +101,7 @@ public function import(mixed $resource, string $type = null, bool $ignoreErrors /** * @internal */ - protected function glob(string $pattern, bool $recursive, array|GlobResource &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable + protected function glob(string $pattern, bool $recursive, array|GlobResource|null &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable { if (\strlen($pattern) === $i = strcspn($pattern, '*?{[')) { $prefix = $pattern; @@ -133,7 +133,7 @@ protected function glob(string $pattern, bool $recursive, array|GlobResource &$r yield from $resource; } - private function doImport(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null): mixed + private function doImport(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null): mixed { try { $loader = $this->resolve($resource, $type); diff --git a/app/vendor/symfony/config/Loader/GlobFileLoader.php b/app/vendor/symfony/config/Loader/GlobFileLoader.php index f921ec555..31eebf69d 100644 --- a/app/vendor/symfony/config/Loader/GlobFileLoader.php +++ b/app/vendor/symfony/config/Loader/GlobFileLoader.php @@ -18,12 +18,12 @@ */ class GlobFileLoader extends FileLoader { - public function load(mixed $resource, string $type = null): mixed + public function load(mixed $resource, ?string $type = null): mixed { return $this->import($resource); } - public function supports(mixed $resource, string $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { return 'glob' === $type; } diff --git a/app/vendor/symfony/config/Loader/Loader.php b/app/vendor/symfony/config/Loader/Loader.php index 36e85ad34..66c38bbea 100644 --- a/app/vendor/symfony/config/Loader/Loader.php +++ b/app/vendor/symfony/config/Loader/Loader.php @@ -23,7 +23,7 @@ abstract class Loader implements LoaderInterface protected $resolver; protected $env; - public function __construct(string $env = null) + public function __construct(?string $env = null) { $this->env = $env; } @@ -46,7 +46,7 @@ public function setResolver(LoaderResolverInterface $resolver) * * @return mixed */ - public function import(mixed $resource, string $type = null) + public function import(mixed $resource, ?string $type = null) { return $this->resolve($resource, $type)->load($resource, $type); } @@ -56,7 +56,7 @@ public function import(mixed $resource, string $type = null) * * @throws LoaderLoadException If no loader is found */ - public function resolve(mixed $resource, string $type = null): LoaderInterface + public function resolve(mixed $resource, ?string $type = null): LoaderInterface { if ($this->supports($resource, $type)) { return $this; diff --git a/app/vendor/symfony/config/Loader/LoaderInterface.php b/app/vendor/symfony/config/Loader/LoaderInterface.php index 4e0746d4d..190d2c630 100644 --- a/app/vendor/symfony/config/Loader/LoaderInterface.php +++ b/app/vendor/symfony/config/Loader/LoaderInterface.php @@ -25,7 +25,7 @@ interface LoaderInterface * * @throws \Exception If something went wrong */ - public function load(mixed $resource, string $type = null); + public function load(mixed $resource, ?string $type = null); /** * Returns whether this class supports the given resource. @@ -34,7 +34,7 @@ public function load(mixed $resource, string $type = null); * * @return bool */ - public function supports(mixed $resource, string $type = null); + public function supports(mixed $resource, ?string $type = null); /** * Gets the loader resolver. diff --git a/app/vendor/symfony/config/Loader/LoaderResolver.php b/app/vendor/symfony/config/Loader/LoaderResolver.php index 670e32012..72ab33411 100644 --- a/app/vendor/symfony/config/Loader/LoaderResolver.php +++ b/app/vendor/symfony/config/Loader/LoaderResolver.php @@ -36,7 +36,7 @@ public function __construct(array $loaders = []) } } - public function resolve(mixed $resource, string $type = null): LoaderInterface|false + public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false { foreach ($this->loaders as $loader) { if ($loader->supports($resource, $type)) { diff --git a/app/vendor/symfony/config/Loader/LoaderResolverInterface.php b/app/vendor/symfony/config/Loader/LoaderResolverInterface.php index 076c5207c..a8bb3a437 100644 --- a/app/vendor/symfony/config/Loader/LoaderResolverInterface.php +++ b/app/vendor/symfony/config/Loader/LoaderResolverInterface.php @@ -23,5 +23,5 @@ interface LoaderResolverInterface * * @param string|null $type The resource type or null if unknown */ - public function resolve(mixed $resource, string $type = null): LoaderInterface|false; + public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false; } diff --git a/app/vendor/symfony/config/Resource/ClassExistenceResource.php b/app/vendor/symfony/config/Resource/ClassExistenceResource.php index 2f262bac8..eab04b8d0 100644 --- a/app/vendor/symfony/config/Resource/ClassExistenceResource.php +++ b/app/vendor/symfony/config/Resource/ClassExistenceResource.php @@ -34,7 +34,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface * @param string $resource The fully-qualified class name * @param bool|null $exists Boolean when the existence check has already been done */ - public function __construct(string $resource, bool $exists = null) + public function __construct(string $resource, ?bool $exists = null) { $this->resource = $resource; if (null !== $exists) { @@ -116,7 +116,7 @@ public function __sleep(): array /** * @internal */ - public function __wakeup() + public function __wakeup(): void { if (\is_bool($this->exists)) { $this->exists = [$this->exists, null]; @@ -139,7 +139,7 @@ public function __wakeup() * * @internal */ - public static function throwOnRequiredClass(string $class, \Exception $previous = null): void + public static function throwOnRequiredClass(string $class, ?\Exception $previous = null): void { // If the passed class is the resource being checked, we shouldn't throw. if (null === $previous && self::$autoloadedClass === $class) { diff --git a/app/vendor/symfony/config/Resource/DirectoryResource.php b/app/vendor/symfony/config/Resource/DirectoryResource.php index 7560cd3b3..df486a085 100644 --- a/app/vendor/symfony/config/Resource/DirectoryResource.php +++ b/app/vendor/symfony/config/Resource/DirectoryResource.php @@ -29,7 +29,7 @@ class DirectoryResource implements SelfCheckingResourceInterface * * @throws \InvalidArgumentException */ - public function __construct(string $resource, string $pattern = null) + public function __construct(string $resource, ?string $pattern = null) { $resolvedResource = realpath($resource) ?: (file_exists($resource) ? $resource : false); $this->pattern = $pattern; diff --git a/app/vendor/symfony/config/Resource/FileExistenceResource.php b/app/vendor/symfony/config/Resource/FileExistenceResource.php index e7b91ff38..666866ee4 100644 --- a/app/vendor/symfony/config/Resource/FileExistenceResource.php +++ b/app/vendor/symfony/config/Resource/FileExistenceResource.php @@ -38,7 +38,7 @@ public function __construct(string $resource) public function __toString(): string { - return $this->resource; + return 'existence.'.$this->resource; } public function getResource(): string diff --git a/app/vendor/symfony/config/Resource/ResourceInterface.php b/app/vendor/symfony/config/Resource/ResourceInterface.php index 4fbe32183..a97671d14 100644 --- a/app/vendor/symfony/config/Resource/ResourceInterface.php +++ b/app/vendor/symfony/config/Resource/ResourceInterface.php @@ -16,7 +16,7 @@ * * @author Fabien Potencier */ -interface ResourceInterface +interface ResourceInterface extends \Stringable { /** * Returns a string representation of the Resource. diff --git a/app/vendor/symfony/config/ResourceCheckerConfigCache.php b/app/vendor/symfony/config/ResourceCheckerConfigCache.php index a8478a8cc..1e58d21ed 100644 --- a/app/vendor/symfony/config/ResourceCheckerConfigCache.php +++ b/app/vendor/symfony/config/ResourceCheckerConfigCache.php @@ -109,7 +109,7 @@ public function isFresh(): bool * * @throws \RuntimeException When cache file can't be written */ - public function write(string $content, array $metadata = null) + public function write(string $content, ?array $metadata = null) { $mode = 0666; $umask = umask(); @@ -150,7 +150,7 @@ private function safelyUnserialize(string $file): mixed $signalingException = new \UnexpectedValueException(); $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) { - if (__FILE__ === $file) { + if (__FILE__ === $file && !\in_array($type, [\E_DEPRECATED, \E_USER_DEPRECATED], true)) { throw $signalingException; } diff --git a/app/vendor/symfony/config/Util/XmlUtils.php b/app/vendor/symfony/config/Util/XmlUtils.php index cc024da46..eb6f0f51a 100644 --- a/app/vendor/symfony/config/Util/XmlUtils.php +++ b/app/vendor/symfony/config/Util/XmlUtils.php @@ -42,7 +42,7 @@ private function __construct() * @throws InvalidXmlException When parsing of XML with schema or callable produces any errors unrelated to the XML parsing itself * @throws \RuntimeException When DOM extension is missing */ - public static function parse(string $content, string|callable $schemaOrCallable = null): \DOMDocument + public static function parse(string $content, string|callable|null $schemaOrCallable = null): \DOMDocument { if (!\extension_loaded('dom')) { throw new \LogicException('Extension DOM is required.'); @@ -112,7 +112,7 @@ public static function parse(string $content, string|callable $schemaOrCallable * @throws XmlParsingException When XML parsing returns any errors * @throws \RuntimeException When DOM extension is missing */ - public static function loadFile(string $file, string|callable $schemaOrCallable = null): \DOMDocument + public static function loadFile(string $file, string|callable|null $schemaOrCallable = null): \DOMDocument { if (!is_file($file)) { throw new \InvalidArgumentException(sprintf('Resource "%s" is not a file.', $file)); diff --git a/app/vendor/symfony/config/composer.json b/app/vendor/symfony/config/composer.json index a4b72c36a..dbd34f13b 100644 --- a/app/vendor/symfony/config/composer.json +++ b/app/vendor/symfony/config/composer.json @@ -18,15 +18,15 @@ "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", "symfony/polyfill-ctype": "~1.8" }, "require-dev": { - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0" + "symfony/yaml": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/finder": "<5.4", diff --git a/app/vendor/symfony/console/Application.php b/app/vendor/symfony/console/Application.php index b7aaa6a29..dc710e8cc 100644 --- a/app/vendor/symfony/console/Application.php +++ b/app/vendor/symfony/console/Application.php @@ -79,6 +79,7 @@ class Application implements ResetInterface private string $version; private ?CommandLoaderInterface $commandLoader = null; private bool $catchExceptions = true; + private bool $catchErrors = false; private bool $autoExit = true; private InputDefinition $definition; private HelperSet $helperSet; @@ -142,7 +143,7 @@ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) * * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. */ - public function run(InputInterface $input = null, OutputInterface $output = null): int + public function run(?InputInterface $input = null, ?OutputInterface $output = null): int { if (\function_exists('putenv')) { @putenv('LINES='.$this->terminal->getHeight()); @@ -168,12 +169,15 @@ public function run(InputInterface $input = null, OutputInterface $output = null } } - $this->configureIO($input, $output); - try { + $this->configureIO($input, $output); + $exitCode = $this->doRun($input, $output); - } catch (\Exception $e) { - if (!$this->catchExceptions) { + } catch (\Throwable $e) { + if ($e instanceof \Exception && !$this->catchExceptions) { + throw $e; + } + if (!$e instanceof \Exception && !$this->catchErrors) { throw $e; } @@ -427,6 +431,14 @@ public function setCatchExceptions(bool $boolean) $this->catchExceptions = $boolean; } + /** + * Sets whether to catch errors or not during commands execution. + */ + public function setCatchErrors(bool $catchErrors = true): void + { + $this->catchErrors = $catchErrors; + } + /** * Gets whether to automatically exit after a command execution or not. */ @@ -783,7 +795,7 @@ public function find(string $name) * * @return Command[] */ - public function all(string $namespace = null) + public function all(?string $namespace = null) { $this->init(); @@ -863,7 +875,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo } if (str_contains($message, "@anonymous\0")) { - $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message); + $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message); } $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; @@ -1034,7 +1046,10 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI } if (false !== $exitCode) { - exit($exitCode); + $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal); + $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); + + exit($event->getExitCode()); } }); } @@ -1162,7 +1177,7 @@ private function getAbbreviationSuggestions(array $abbrevs): string * * This method is not part of public API and should not be used directly. */ - public function extractNamespace(string $name, int $limit = null): string + public function extractNamespace(string $name, ?int $limit = null): string { $parts = explode(':', $name, -1); diff --git a/app/vendor/symfony/console/CHANGELOG.md b/app/vendor/symfony/console/CHANGELOG.md index 3428a57de..9ccb41d94 100644 --- a/app/vendor/symfony/console/CHANGELOG.md +++ b/app/vendor/symfony/console/CHANGELOG.md @@ -1,6 +1,15 @@ CHANGELOG ========= +6.4 +--- + + * Add `SignalMap` to map signal value to its name + * Multi-line text in vertical tables is aligned properly + * The application can also catch errors with `Application::setCatchErrors(true)` + * Add `RunCommandMessage` and `RunCommandMessageHandler` + * Dispatch `ConsoleTerminateEvent` after an exit on signal handling and add `ConsoleTerminateEvent::getInterruptingSignal()` + 6.3 --- diff --git a/app/vendor/symfony/console/CI/GithubActionReporter.php b/app/vendor/symfony/console/CI/GithubActionReporter.php index 7e5565469..2cae6fd8b 100644 --- a/app/vendor/symfony/console/CI/GithubActionReporter.php +++ b/app/vendor/symfony/console/CI/GithubActionReporter.php @@ -57,7 +57,7 @@ public static function isGithubActionEnvironment(): bool * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message */ - public function error(string $message, string $file = null, int $line = null, int $col = null): void + public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { $this->log('error', $message, $file, $line, $col); } @@ -67,7 +67,7 @@ public function error(string $message, string $file = null, int $line = null, in * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message */ - public function warning(string $message, string $file = null, int $line = null, int $col = null): void + public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { $this->log('warning', $message, $file, $line, $col); } @@ -77,12 +77,12 @@ public function warning(string $message, string $file = null, int $line = null, * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message */ - public function debug(string $message, string $file = null, int $line = null, int $col = null): void + public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { $this->log('debug', $message, $file, $line, $col); } - private function log(string $type, string $message, string $file = null, int $line = null, int $col = null): void + private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { // Some values must be encoded. $message = strtr($message, self::ESCAPED_DATA); diff --git a/app/vendor/symfony/console/Command/Command.php b/app/vendor/symfony/console/Command/Command.php index 704b112d1..9f9cb2f53 100644 --- a/app/vendor/symfony/console/Command/Command.php +++ b/app/vendor/symfony/console/Command/Command.php @@ -111,7 +111,7 @@ public static function getDefaultDescription(): ?string * * @throws LogicException When the command name is empty */ - public function __construct(string $name = null) + public function __construct(?string $name = null) { $this->definition = new InputDefinition(); @@ -152,7 +152,7 @@ public function ignoreValidationErrors() /** * @return void */ - public function setApplication(Application $application = null) + public function setApplication(?Application $application = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -460,7 +460,7 @@ public function getNativeDefinition(): InputDefinition * * @throws InvalidArgumentException When argument mode is not valid */ - public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { @@ -484,7 +484,7 @@ public function addArgument(string $name, int $mode = null, string $description * * @throws InvalidArgumentException If option mode is invalid or incompatible */ - public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { diff --git a/app/vendor/symfony/console/Command/CompleteCommand.php b/app/vendor/symfony/console/Command/CompleteCommand.php index 058578d8b..23be5577b 100644 --- a/app/vendor/symfony/console/Command/CompleteCommand.php +++ b/app/vendor/symfony/console/Command/CompleteCommand.php @@ -44,9 +44,9 @@ final class CompleteCommand extends Command */ protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; - private $completionOutputs; + private array $completionOutputs; - private $isDebug = false; + private bool $isDebug = false; /** * @param array> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value diff --git a/app/vendor/symfony/console/Command/LazyCommand.php b/app/vendor/symfony/console/Command/LazyCommand.php index d56058221..b94da6665 100644 --- a/app/vendor/symfony/console/Command/LazyCommand.php +++ b/app/vendor/symfony/console/Command/LazyCommand.php @@ -45,7 +45,7 @@ public function ignoreValidationErrors(): void $this->getCommand()->ignoreValidationErrors(); } - public function setApplication(Application $application = null): void + public function setApplication(?Application $application = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -116,7 +116,7 @@ public function getNativeDefinition(): InputDefinition /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ - public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues); @@ -127,7 +127,7 @@ public function addArgument(string $name, int $mode = null, string $description /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ - public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); diff --git a/app/vendor/symfony/console/Command/LockableTrait.php b/app/vendor/symfony/console/Command/LockableTrait.php index c1006a65c..cd7548f02 100644 --- a/app/vendor/symfony/console/Command/LockableTrait.php +++ b/app/vendor/symfony/console/Command/LockableTrait.php @@ -29,7 +29,7 @@ trait LockableTrait /** * Locks a command. */ - private function lock(string $name = null, bool $blocking = false): bool + 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. Try running "composer require symfony/lock".'); diff --git a/app/vendor/symfony/console/Command/SignalableCommandInterface.php b/app/vendor/symfony/console/Command/SignalableCommandInterface.php index 4d0876003..f8eb8e522 100644 --- a/app/vendor/symfony/console/Command/SignalableCommandInterface.php +++ b/app/vendor/symfony/console/Command/SignalableCommandInterface.php @@ -27,7 +27,7 @@ public function getSubscribedSignals(): array; * 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, /* int|false $previousExitCode = 0 */); diff --git a/app/vendor/symfony/console/Command/TraceableCommand.php b/app/vendor/symfony/console/Command/TraceableCommand.php new file mode 100644 index 000000000..9ffb68da3 --- /dev/null +++ b/app/vendor/symfony/console/Command/TraceableCommand.php @@ -0,0 +1,356 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Helper\HelperInterface; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @internal + * + * @author Jules Pietri + */ +final class TraceableCommand extends Command implements SignalableCommandInterface +{ + public readonly Command $command; + public int $exitCode; + public ?int $interruptedBySignal = null; + public bool $ignoreValidation; + public bool $isInteractive = false; + public string $duration = 'n/a'; + public string $maxMemoryUsage = 'n/a'; + public InputInterface $input; + public OutputInterface $output; + /** @var array */ + public array $arguments; + /** @var array */ + public array $options; + /** @var array */ + public array $interactiveInputs = []; + public array $handledSignals = []; + + public function __construct( + Command $command, + private readonly Stopwatch $stopwatch, + ) { + if ($command instanceof LazyCommand) { + $command = $command->getCommand(); + } + + $this->command = $command; + + // prevent call to self::getDefaultDescription() + $this->setDescription($command->getDescription()); + + parent::__construct($command->getName()); + + // init below enables calling {@see parent::run()} + [$code, $processTitle, $ignoreValidationErrors] = \Closure::bind(function () { + return [$this->code, $this->processTitle, $this->ignoreValidationErrors]; + }, $command, Command::class)(); + + if (\is_callable($code)) { + $this->setCode($code); + } + + if ($processTitle) { + parent::setProcessTitle($processTitle); + } + + if ($ignoreValidationErrors) { + parent::ignoreValidationErrors(); + } + + $this->ignoreValidation = $ignoreValidationErrors; + } + + public function __call(string $name, array $arguments): mixed + { + return $this->command->{$name}(...$arguments); + } + + public function getSubscribedSignals(): array + { + return $this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : []; + } + + public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false + { + if (!$this->command instanceof SignalableCommandInterface) { + return false; + } + + $event = $this->stopwatch->start($this->getName().'.handle_signal'); + + $exit = $this->command->handleSignal($signal, $previousExitCode); + + $event->stop(); + + if (!isset($this->handledSignals[$signal])) { + $this->handledSignals[$signal] = [ + 'handled' => 0, + 'duration' => 0, + 'memory' => 0, + ]; + } + + ++$this->handledSignals[$signal]['handled']; + $this->handledSignals[$signal]['duration'] += $event->getDuration(); + $this->handledSignals[$signal]['memory'] = max( + $this->handledSignals[$signal]['memory'], + $event->getMemory() >> 20 + ); + + return $exit; + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function ignoreValidationErrors(): void + { + $this->ignoreValidation = true; + $this->command->ignoreValidationErrors(); + + parent::ignoreValidationErrors(); + } + + public function setApplication(?Application $application = null): void + { + $this->command->setApplication($application); + } + + public function getApplication(): ?Application + { + return $this->command->getApplication(); + } + + public function setHelperSet(HelperSet $helperSet): void + { + $this->command->setHelperSet($helperSet); + } + + public function getHelperSet(): ?HelperSet + { + return $this->command->getHelperSet(); + } + + public function isEnabled(): bool + { + return $this->command->isEnabled(); + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + $this->command->complete($input, $suggestions); + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function setCode(callable $code): static + { + $this->command->setCode($code); + + return parent::setCode(function (InputInterface $input, OutputInterface $output) use ($code): int { + $event = $this->stopwatch->start($this->getName().'.code'); + + $this->exitCode = $code($input, $output); + + $event->stop(); + + return $this->exitCode; + }); + } + + /** + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = true): void + { + $this->command->mergeApplicationDefinition($mergeArgs); + } + + public function setDefinition(array|InputDefinition $definition): static + { + $this->command->setDefinition($definition); + + return $this; + } + + public function getDefinition(): InputDefinition + { + return $this->command->getDefinition(); + } + + public function getNativeDefinition(): InputDefinition + { + return $this->command->getNativeDefinition(); + } + + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static + { + $this->command->addArgument($name, $mode, $description, $default, $suggestedValues); + + return $this; + } + + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static + { + $this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); + + return $this; + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function setProcessTitle(string $title): static + { + $this->command->setProcessTitle($title); + + return parent::setProcessTitle($title); + } + + public function setHelp(string $help): static + { + $this->command->setHelp($help); + + return $this; + } + + public function getHelp(): string + { + return $this->command->getHelp(); + } + + public function getProcessedHelp(): string + { + return $this->command->getProcessedHelp(); + } + + public function getSynopsis(bool $short = false): string + { + return $this->command->getSynopsis($short); + } + + public function addUsage(string $usage): static + { + $this->command->addUsage($usage); + + return $this; + } + + public function getUsages(): array + { + return $this->command->getUsages(); + } + + public function getHelper(string $name): HelperInterface + { + return $this->command->getHelper($name); + } + + public function run(InputInterface $input, OutputInterface $output): int + { + $this->input = $input; + $this->output = $output; + $this->arguments = $input->getArguments(); + $this->options = $input->getOptions(); + $event = $this->stopwatch->start($this->getName(), 'command'); + + try { + $this->exitCode = parent::run($input, $output); + } finally { + $event->stop(); + + if ($output instanceof ConsoleOutputInterface && $output->isDebug()) { + $output->getErrorOutput()->writeln((string) $event); + } + + $this->duration = $event->getDuration().' ms'; + $this->maxMemoryUsage = ($event->getMemory() >> 20).' MiB'; + + if ($this->isInteractive) { + $this->extractInteractiveInputs($input->getArguments(), $input->getOptions()); + } + } + + return $this->exitCode; + } + + protected function initialize(InputInterface $input, OutputInterface $output): void + { + $event = $this->stopwatch->start($this->getName().'.init', 'command'); + + $this->command->initialize($input, $output); + + $event->stop(); + } + + protected function interact(InputInterface $input, OutputInterface $output): void + { + if (!$this->isInteractive = Command::class !== (new \ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName()) { + return; + } + + $event = $this->stopwatch->start($this->getName().'.interact', 'command'); + + $this->command->interact($input, $output); + + $event->stop(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $event = $this->stopwatch->start($this->getName().'.execute', 'command'); + + $exitCode = $this->command->execute($input, $output); + + $event->stop(); + + return $exitCode; + } + + private function extractInteractiveInputs(array $arguments, array $options): void + { + foreach ($arguments as $argName => $argValue) { + if (\array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) { + continue; + } + + $this->interactiveInputs[$argName] = $argValue; + } + + foreach ($options as $optName => $optValue) { + if (\array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) { + continue; + } + + $this->interactiveInputs['--'.$optName] = $optValue; + } + } +} diff --git a/app/vendor/symfony/console/Completion/CompletionInput.php b/app/vendor/symfony/console/Completion/CompletionInput.php index 800b7235a..79c2f659a 100644 --- a/app/vendor/symfony/console/Completion/CompletionInput.php +++ b/app/vendor/symfony/console/Completion/CompletionInput.php @@ -31,11 +31,11 @@ final class CompletionInput extends ArgvInput public const TYPE_OPTION_NAME = 'option_name'; public const TYPE_NONE = 'none'; - private $tokens; - private $currentIndex; - private $completionType; - private $completionName; - private $completionValue = ''; + private array $tokens; + private int $currentIndex; + private string $completionType; + private ?string $completionName = null; + private string $completionValue = ''; /** * Converts a terminal string into tokens. @@ -53,7 +53,7 @@ public static function fromString(string $inputStr, int $currentIndex): self * Create an input based on an COMP_WORDS token list. * * @param string[] $tokens the set of split tokens (e.g. COMP_WORDS or argv) - * @param $currentIndex the index of the cursor (e.g. COMP_CWORD) + * @param int $currentIndex the index of the cursor (e.g. COMP_CWORD) */ public static function fromTokens(array $tokens, int $currentIndex): self { @@ -141,7 +141,9 @@ public function bind(InputDefinition $definition): void * TYPE_OPTION_NAME when completing the name of an input option * TYPE_NONE when nothing should be completed * - * @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component + * TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component. + * + * @return self::TYPE_* */ public function getCompletionType(): string { diff --git a/app/vendor/symfony/console/Completion/CompletionSuggestions.php b/app/vendor/symfony/console/Completion/CompletionSuggestions.php index 719118177..549bbafbd 100644 --- a/app/vendor/symfony/console/Completion/CompletionSuggestions.php +++ b/app/vendor/symfony/console/Completion/CompletionSuggestions.php @@ -20,8 +20,8 @@ */ final class CompletionSuggestions { - private $valueSuggestions = []; - private $optionSuggestions = []; + private array $valueSuggestions = []; + private array $optionSuggestions = []; /** * Add a suggested value for an input option or argument. diff --git a/app/vendor/symfony/console/Cursor.php b/app/vendor/symfony/console/Cursor.php index b7f5a17e0..69fd3821c 100644 --- a/app/vendor/symfony/console/Cursor.php +++ b/app/vendor/symfony/console/Cursor.php @@ -19,6 +19,7 @@ final class Cursor { private OutputInterface $output; + /** @var resource */ private $input; /** diff --git a/app/vendor/symfony/console/DataCollector/CommandDataCollector.php b/app/vendor/symfony/console/DataCollector/CommandDataCollector.php new file mode 100644 index 000000000..45138c7dc --- /dev/null +++ b/app/vendor/symfony/console/DataCollector/CommandDataCollector.php @@ -0,0 +1,234 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\DataCollector; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Debug\CliRequest; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\SignalRegistry\SignalMap; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * @internal + * + * @author Jules Pietri + */ +final class CommandDataCollector extends DataCollector +{ + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void + { + if (!$request instanceof CliRequest) { + return; + } + + $command = $request->command; + $application = $command->getApplication(); + + $this->data = [ + 'command' => $this->cloneVar($command->command), + 'exit_code' => $command->exitCode, + 'interrupted_by_signal' => $command->interruptedBySignal, + 'duration' => $command->duration, + 'max_memory_usage' => $command->maxMemoryUsage, + 'verbosity_level' => match ($command->output->getVerbosity()) { + OutputInterface::VERBOSITY_QUIET => 'quiet', + OutputInterface::VERBOSITY_NORMAL => 'normal', + OutputInterface::VERBOSITY_VERBOSE => 'verbose', + OutputInterface::VERBOSITY_VERY_VERBOSE => 'very verbose', + OutputInterface::VERBOSITY_DEBUG => 'debug', + }, + 'interactive' => $command->isInteractive, + 'validate_input' => !$command->ignoreValidation, + 'enabled' => $command->isEnabled(), + 'visible' => !$command->isHidden(), + 'input' => $this->cloneVar($command->input), + 'output' => $this->cloneVar($command->output), + 'interactive_inputs' => array_map($this->cloneVar(...), $command->interactiveInputs), + 'signalable' => $command->getSubscribedSignals(), + 'handled_signals' => $command->handledSignals, + 'helper_set' => array_map($this->cloneVar(...), iterator_to_array($command->getHelperSet())), + ]; + + $baseDefinition = $application->getDefinition(); + + foreach ($command->arguments as $argName => $argValue) { + if ($baseDefinition->hasArgument($argName)) { + $this->data['application_inputs'][$argName] = $this->cloneVar($argValue); + } else { + $this->data['arguments'][$argName] = $this->cloneVar($argValue); + } + } + + foreach ($command->options as $optName => $optValue) { + if ($baseDefinition->hasOption($optName)) { + $this->data['application_inputs']['--'.$optName] = $this->cloneVar($optValue); + } else { + $this->data['options'][$optName] = $this->cloneVar($optValue); + } + } + } + + public function getName(): string + { + return 'command'; + } + + /** + * @return array{ + * class?: class-string, + * executor?: string, + * file: string, + * line: int, + * } + */ + public function getCommand(): array + { + $class = $this->data['command']->getType(); + $r = new \ReflectionMethod($class, 'execute'); + + if (Command::class !== $r->getDeclaringClass()) { + return [ + 'executor' => $class.'::'.$r->name, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + } + + $r = new \ReflectionClass($class); + + return [ + 'class' => $class, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + } + + public function getInterruptedBySignal(): ?string + { + if (isset($this->data['interrupted_by_signal'])) { + return sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); + } + + return null; + } + + public function getDuration(): string + { + return $this->data['duration']; + } + + public function getMaxMemoryUsage(): string + { + return $this->data['max_memory_usage']; + } + + public function getVerbosityLevel(): string + { + return $this->data['verbosity_level']; + } + + public function getInteractive(): bool + { + return $this->data['interactive']; + } + + public function getValidateInput(): bool + { + return $this->data['validate_input']; + } + + public function getEnabled(): bool + { + return $this->data['enabled']; + } + + public function getVisible(): bool + { + return $this->data['visible']; + } + + public function getInput(): Data + { + return $this->data['input']; + } + + public function getOutput(): Data + { + return $this->data['output']; + } + + /** + * @return Data[] + */ + public function getArguments(): array + { + return $this->data['arguments'] ?? []; + } + + /** + * @return Data[] + */ + public function getOptions(): array + { + return $this->data['options'] ?? []; + } + + /** + * @return Data[] + */ + public function getApplicationInputs(): array + { + return $this->data['application_inputs'] ?? []; + } + + /** + * @return Data[] + */ + public function getInteractiveInputs(): array + { + return $this->data['interactive_inputs'] ?? []; + } + + public function getSignalable(): array + { + return array_map( + static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + $this->data['signalable'] + ); + } + + public function getHandledSignals(): array + { + $keys = array_map( + static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + array_keys($this->data['handled_signals']) + ); + + return array_combine($keys, array_values($this->data['handled_signals'])); + } + + /** + * @return Data[] + */ + public function getHelperSet(): array + { + return $this->data['helper_set'] ?? []; + } + + public function reset(): void + { + $this->data = []; + } +} diff --git a/app/vendor/symfony/console/Debug/CliRequest.php b/app/vendor/symfony/console/Debug/CliRequest.php new file mode 100644 index 000000000..b023db07a --- /dev/null +++ b/app/vendor/symfony/console/Debug/CliRequest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Debug; + +use Symfony\Component\Console\Command\TraceableCommand; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * @internal + */ +final class CliRequest extends Request +{ + public function __construct( + public readonly TraceableCommand $command, + ) { + parent::__construct( + attributes: ['_controller' => \get_class($command->command), '_virtual_type' => 'command'], + server: $_SERVER, + ); + } + + // Methods below allow to populate a profile, thus enable search and filtering + public function getUri(): string + { + if ($this->server->has('SYMFONY_CLI_BINARY_NAME')) { + $binary = $this->server->get('SYMFONY_CLI_BINARY_NAME').' console'; + } else { + $binary = $this->server->get('argv')[0]; + } + + return $binary.' '.$this->command->input; + } + + public function getMethod(): string + { + return $this->command->isInteractive ? 'INTERACTIVE' : 'BATCH'; + } + + public function getResponse(): Response + { + return new class($this->command->exitCode) extends Response { + public function __construct(private readonly int $exitCode) + { + parent::__construct(); + } + + public function getStatusCode(): int + { + return $this->exitCode; + } + }; + } + + public function getClientIp(): string + { + $application = $this->command->getApplication(); + + return $application->getName().' '.$application->getVersion(); + } +} diff --git a/app/vendor/symfony/console/Descriptor/ApplicationDescription.php b/app/vendor/symfony/console/Descriptor/ApplicationDescription.php index f8ed18045..ef9e8a63b 100644 --- a/app/vendor/symfony/console/Descriptor/ApplicationDescription.php +++ b/app/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -39,7 +39,7 @@ class ApplicationDescription */ private array $aliases = []; - public function __construct(Application $application, string $namespace = null, bool $showHidden = false) + public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false) { $this->application = $application; $this->namespace = $namespace; diff --git a/app/vendor/symfony/console/Descriptor/XmlDescriptor.php b/app/vendor/symfony/console/Descriptor/XmlDescriptor.php index 72580fd98..866c71856 100644 --- a/app/vendor/symfony/console/Descriptor/XmlDescriptor.php +++ b/app/vendor/symfony/console/Descriptor/XmlDescriptor.php @@ -79,7 +79,7 @@ public function getCommandDocument(Command $command, bool $short = false): \DOMD return $dom; } - public function getApplicationDocument(Application $application, string $namespace = null, bool $short = false): \DOMDocument + public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($rootXml = $dom->createElement('symfony')); diff --git a/app/vendor/symfony/console/Event/ConsoleCommandEvent.php b/app/vendor/symfony/console/Event/ConsoleCommandEvent.php index 31c9ee99a..0757a23f6 100644 --- a/app/vendor/symfony/console/Event/ConsoleCommandEvent.php +++ b/app/vendor/symfony/console/Event/ConsoleCommandEvent.php @@ -12,7 +12,10 @@ namespace Symfony\Component\Console\Event; /** - * Allows to do things before the command is executed, like skipping the command or changing the input. + * Allows to do things before the command is executed, like skipping the command or executing code before the command is + * going to be executed. + * + * Changing the input arguments will have no effect. * * @author Fabien Potencier */ diff --git a/app/vendor/symfony/console/Event/ConsoleErrorEvent.php b/app/vendor/symfony/console/Event/ConsoleErrorEvent.php index d4a691216..7be2ff83e 100644 --- a/app/vendor/symfony/console/Event/ConsoleErrorEvent.php +++ b/app/vendor/symfony/console/Event/ConsoleErrorEvent.php @@ -25,7 +25,7 @@ final class ConsoleErrorEvent extends ConsoleEvent private \Throwable $error; private int $exitCode; - public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null) + public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null) { parent::__construct($command, $input, $output); diff --git a/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php b/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php index de63c8ffa..38f7253a5 100644 --- a/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php +++ b/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php @@ -19,16 +19,18 @@ * Allows to manipulate the exit code of a command after its execution. * * @author Francesco Levorato + * @author Jules Pietri */ final class ConsoleTerminateEvent extends ConsoleEvent { - private int $exitCode; - - public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode) - { + public function __construct( + Command $command, + InputInterface $input, + OutputInterface $output, + private int $exitCode, + private readonly ?int $interruptingSignal = null, + ) { parent::__construct($command, $input, $output); - - $this->setExitCode($exitCode); } public function setExitCode(int $exitCode): void @@ -40,4 +42,9 @@ public function getExitCode(): int { return $this->exitCode; } + + public function getInterruptingSignal(): ?int + { + return $this->interruptingSignal; + } } diff --git a/app/vendor/symfony/console/EventListener/ErrorListener.php b/app/vendor/symfony/console/EventListener/ErrorListener.php index 9925a5f74..c9ec24434 100644 --- a/app/vendor/symfony/console/EventListener/ErrorListener.php +++ b/app/vendor/symfony/console/EventListener/ErrorListener.php @@ -26,7 +26,7 @@ class ErrorListener implements EventSubscriberInterface { private ?LoggerInterface $logger; - public function __construct(LoggerInterface $logger = null) + public function __construct(?LoggerInterface $logger = null) { $this->logger = $logger; } diff --git a/app/vendor/symfony/console/Exception/CommandNotFoundException.php b/app/vendor/symfony/console/Exception/CommandNotFoundException.php index 1e9f1c793..541b32b23 100644 --- a/app/vendor/symfony/console/Exception/CommandNotFoundException.php +++ b/app/vendor/symfony/console/Exception/CommandNotFoundException.php @@ -26,7 +26,7 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce * @param int $code Exception code * @param \Throwable|null $previous Previous exception used for the exception chaining */ - public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null) + public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); diff --git a/app/vendor/symfony/console/Exception/RunCommandFailedException.php b/app/vendor/symfony/console/Exception/RunCommandFailedException.php new file mode 100644 index 000000000..5d87ec949 --- /dev/null +++ b/app/vendor/symfony/console/Exception/RunCommandFailedException.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +use Symfony\Component\Console\Messenger\RunCommandContext; + +/** + * @author Kevin Bond + */ +final class RunCommandFailedException extends RuntimeException +{ + public function __construct(\Throwable|string $exception, public readonly RunCommandContext $context) + { + parent::__construct( + $exception instanceof \Throwable ? $exception->getMessage() : $exception, + $exception instanceof \Throwable ? $exception->getCode() : 0, + $exception instanceof \Throwable ? $exception : null, + ); + } +} diff --git a/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php b/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php index c2ce7d14c..ae23decb1 100644 --- a/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php +++ b/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php @@ -21,7 +21,7 @@ public function apply(string $text): string return $text; } - public function setBackground(string $color = null): void + public function setBackground(?string $color = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -29,7 +29,7 @@ public function setBackground(string $color = null): void // do nothing } - public function setForeground(string $color = null): void + public function setForeground(?string $color = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php index 346a474c6..21e7f5ab0 100644 --- a/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php +++ b/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -33,7 +33,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface * @param string|null $foreground The style foreground color name * @param string|null $background The style background color name */ - public function __construct(string $foreground = null, string $background = null, array $options = []) + public function __construct(?string $foreground = null, ?string $background = null, array $options = []) { $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); } @@ -41,7 +41,7 @@ public function __construct(string $foreground = null, string $background = null /** * @return void */ - public function setForeground(string $color = null) + public function setForeground(?string $color = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -52,7 +52,7 @@ public function setForeground(string $color = null) /** * @return void */ - public function setBackground(string $color = null) + public function setBackground(?string $color = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php index f98c2eff7..62d2ca0e7 100644 --- a/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php +++ b/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -26,7 +26,7 @@ class OutputFormatterStyleStack implements ResetInterface private OutputFormatterStyleInterface $emptyStyle; - public function __construct(OutputFormatterStyleInterface $emptyStyle = null) + public function __construct(?OutputFormatterStyleInterface $emptyStyle = null) { $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle(); $this->reset(); @@ -57,7 +57,7 @@ public function push(OutputFormatterStyleInterface $style) * * @throws InvalidArgumentException When style tags incorrectly nested */ - public function pop(OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface + public function pop(?OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface { if (!$this->styles) { return $this->emptyStyle; diff --git a/app/vendor/symfony/console/Helper/Dumper.php b/app/vendor/symfony/console/Helper/Dumper.php index 8c6a94d51..a3b8e3952 100644 --- a/app/vendor/symfony/console/Helper/Dumper.php +++ b/app/vendor/symfony/console/Helper/Dumper.php @@ -26,7 +26,7 @@ final class Dumper private ?ClonerInterface $cloner; private \Closure $handler; - public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null) + public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null) { $this->output = $output; $this->dumper = $dumper; diff --git a/app/vendor/symfony/console/Helper/Helper.php b/app/vendor/symfony/console/Helper/Helper.php index 3631b30f6..05be64787 100644 --- a/app/vendor/symfony/console/Helper/Helper.php +++ b/app/vendor/symfony/console/Helper/Helper.php @@ -26,7 +26,7 @@ abstract class Helper implements HelperInterface /** * @return void */ - public function setHelperSet(HelperSet $helperSet = null) + public function setHelperSet(?HelperSet $helperSet = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -80,7 +80,7 @@ public static function length(?string $string): int /** * Returns the subset of a string, using mb_substr if it is available. */ - public static function substr(?string $string, int $from, int $length = null): string + public static function substr(?string $string, int $from, ?int $length = null): string { $string ??= ''; @@ -94,33 +94,44 @@ public static function substr(?string $string, int $from, int $length = null): s /** * @return string */ - public static function formatTime(int|float $secs) + public static function formatTime(int|float $secs, int $precision = 1) { + $secs = (int) floor($secs); + + if (0 === $secs) { + return '< 1 sec'; + } + static $timeFormats = [ - [0, '< 1 sec'], - [1, '1 sec'], - [2, 'secs', 1], - [60, '1 min'], - [120, 'mins', 60], - [3600, '1 hr'], - [7200, 'hrs', 3600], - [86400, '1 day'], - [172800, 'days', 86400], + [1, '1 sec', 'secs'], + [60, '1 min', 'mins'], + [3600, '1 hr', 'hrs'], + [86400, '1 day', 'days'], ]; + $times = []; foreach ($timeFormats as $index => $format) { - if ($secs >= $format[0]) { - if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0]) - || $index == \count($timeFormats) - 1 - ) { - if (2 == \count($format)) { - return $format[1]; - } - - return floor($secs / $format[2]).' '.$format[1]; - } + $seconds = isset($timeFormats[$index + 1]) ? $secs % $timeFormats[$index + 1][0] : $secs; + + if (isset($times[$index - $precision])) { + unset($times[$index - $precision]); + } + + if (0 === $seconds) { + continue; } + + $unitCount = ($seconds / $format[0]); + $times[$index] = 1 === $unitCount ? $format[1] : $unitCount.' '.$format[2]; + + if ($secs === $seconds) { + break; + } + + $secs -= $seconds; } + + return implode(', ', array_reverse($times)); } /** diff --git a/app/vendor/symfony/console/Helper/HelperSet.php b/app/vendor/symfony/console/Helper/HelperSet.php index dc5d499ca..f8c74ca2c 100644 --- a/app/vendor/symfony/console/Helper/HelperSet.php +++ b/app/vendor/symfony/console/Helper/HelperSet.php @@ -38,7 +38,7 @@ public function __construct(array $helpers = []) /** * @return void */ - public function set(HelperInterface $helper, string $alias = null) + public function set(HelperInterface $helper, ?string $alias = null) { $this->helpers[$helper->getName()] = $helper; if (null !== $alias) { diff --git a/app/vendor/symfony/console/Helper/ProcessHelper.php b/app/vendor/symfony/console/Helper/ProcessHelper.php index 26d35a1a8..3ef6f71f7 100644 --- a/app/vendor/symfony/console/Helper/ProcessHelper.php +++ b/app/vendor/symfony/console/Helper/ProcessHelper.php @@ -32,7 +32,7 @@ class ProcessHelper extends Helper * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR */ - public function run(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process + public function run(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process { if (!class_exists(Process::class)) { throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); @@ -94,7 +94,7 @@ public function run(OutputInterface $output, array|Process $cmd, string $error = * * @see run() */ - public function mustRun(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null): Process + public function mustRun(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null): Process { $process = $this->run($output, $cmd, $error, $callback); @@ -108,7 +108,7 @@ public function mustRun(OutputInterface $output, array|Process $cmd, string $err /** * Wraps a Process callback to add debugging output. */ - public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null): callable + public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); diff --git a/app/vendor/symfony/console/Helper/ProgressBar.php b/app/vendor/symfony/console/Helper/ProgressBar.php index 19faea47c..3dc06d7b4 100644 --- a/app/vendor/symfony/console/Helper/ProgressBar.php +++ b/app/vendor/symfony/console/Helper/ProgressBar.php @@ -183,9 +183,9 @@ public function setMessage(string $message, string $name = 'message'): void $this->messages[$name] = $message; } - public function getMessage(string $name = 'message'): string + public function getMessage(string $name = 'message'): ?string { - return $this->messages[$name]; + return $this->messages[$name] ?? null; } public function getStartTime(): int @@ -229,7 +229,7 @@ public function getEstimated(): float public function getRemaining(): float { - if (!$this->step) { + if (0 === $this->step || $this->step === $this->startingStep) { return 0; } @@ -305,9 +305,15 @@ public function maxSecondsBetweenRedraws(float $seconds): void /** * Returns an iterator that will automatically update the progress bar when iterated. * - * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable */ - public function iterate(iterable $iterable, int $max = null): iterable + public function iterate(iterable $iterable, ?int $max = null): iterable { $this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0)); @@ -326,7 +332,7 @@ public function iterate(iterable $iterable, int $max = null): iterable * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged * @param int $startAt The starting point of the bar (useful e.g. when resuming a previously started bar) */ - public function start(int $max = null, int $startAt = 0): void + public function start(?int $max = null, int $startAt = 0): void { $this->startTime = time(); $this->step = $startAt; @@ -480,12 +486,21 @@ private function overwrite(string $message): void if ($this->output instanceof ConsoleSectionOutput) { $messageLines = explode("\n", $this->previousMessage); $lineCount = \count($messageLines); + + $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? ''); + + // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again + if ('' === $lastLineWithoutDecoration) { + --$lineCount; + } + foreach ($messageLines as $messageLine) { $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); if ($messageLineLength > $this->terminal->getWidth()) { $lineCount += floor($messageLineLength / $this->terminal->getWidth()); } } + $this->output->clear($lineCount); } else { $lineCount = substr_count($this->previousMessage, "\n"); @@ -534,20 +549,20 @@ private static function initPlaceholderFormatters(): array return $display; }, - 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime()), + 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime(), 2), '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.'); } - return Helper::formatTime($bar->getRemaining()); + return Helper::formatTime($bar->getRemaining(), 2); }, 'estimated' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); } - return Helper::formatTime($bar->getEstimated()); + return Helper::formatTime($bar->getEstimated(), 2); }, 'memory' => fn (self $bar) => Helper::formatMemory(memory_get_usage(true)), 'current' => fn (self $bar) => str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT), diff --git a/app/vendor/symfony/console/Helper/ProgressIndicator.php b/app/vendor/symfony/console/Helper/ProgressIndicator.php index 84dbef950..92106caf6 100644 --- a/app/vendor/symfony/console/Helper/ProgressIndicator.php +++ b/app/vendor/symfony/console/Helper/ProgressIndicator.php @@ -50,7 +50,7 @@ class ProgressIndicator * @param int $indicatorChangeInterval Change interval in milliseconds * @param array|null $indicatorValues Animated indicator characters */ - public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null) + public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null) { $this->output = $output; @@ -228,7 +228,7 @@ private static function initPlaceholderFormatters(): array return [ '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), + 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime, 2), 'memory' => fn () => Helper::formatMemory(memory_get_usage(true)), ]; } diff --git a/app/vendor/symfony/console/Helper/QuestionHelper.php b/app/vendor/symfony/console/Helper/QuestionHelper.php index f32813c6c..b40b13191 100644 --- a/app/vendor/symfony/console/Helper/QuestionHelper.php +++ b/app/vendor/symfony/console/Helper/QuestionHelper.php @@ -501,19 +501,7 @@ private function isInteractiveInput($inputStream): bool return self::$stdinIsInteractive; } - if (\function_exists('stream_isatty')) { - return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); - } - - if (\function_exists('posix_isatty')) { - return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); - } - - if (!\function_exists('shell_exec')) { - return self::$stdinIsInteractive = true; - } - - return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); + return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); } /** diff --git a/app/vendor/symfony/console/Helper/Table.php b/app/vendor/symfony/console/Helper/Table.php index cf714873f..1f026dc50 100644 --- a/app/vendor/symfony/console/Helper/Table.php +++ b/app/vendor/symfony/console/Helper/Table.php @@ -364,14 +364,28 @@ public function render() $maxRows = max(\count($headers), \count($row)); for ($i = 0; $i < $maxRows; ++$i) { $cell = (string) ($row[$i] ?? ''); - if ($headers && !$containsColspan) { - $rows[] = [sprintf( - '%s: %s', - str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), - $cell - )]; - } elseif ('' !== $cell) { - $rows[] = [$cell]; + + $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n"; + $parts = explode($eol, $cell); + foreach ($parts as $idx => $part) { + if ($headers && !$containsColspan) { + if (0 === $idx) { + $rows[] = [sprintf( + '%s%s: %s', + str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))), + $headers[$i] ?? '', + $part + )]; + } else { + $rows[] = [sprintf( + '%s %s', + str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), + $part + )]; + } + } elseif ('' !== $cell) { + $rows[] = [$part]; + } } } } @@ -411,7 +425,7 @@ public function render() if ($isHeader && !$isHeaderSeparatorRendered) { $this->renderRowSeparator( - $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, + self::SEPARATOR_TOP, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); @@ -421,7 +435,7 @@ public function render() if ($isFirstRow) { $this->renderRowSeparator( - $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, + $horizontal ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); @@ -454,7 +468,7 @@ public function render() * * +-----+-----------+-------+ */ - private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null): void + private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null): void { if (!$count = $this->numberOfColumns) { return; @@ -519,7 +533,7 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string * * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | */ - private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null): void + private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null): void { $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); $columns = $this->getRowColumns($row); @@ -624,9 +638,10 @@ private function buildTableRows(array $rows): TableRows if (!str_contains($cell ?? '', "\n")) { continue; } - $escaped = implode("\n", array_map(OutputFormatter::escapeTrailingBackslash(...), explode("\n", $cell))); + $eol = str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n"; + $escaped = implode($eol, array_map(OutputFormatter::escapeTrailingBackslash(...), explode($eol, $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; - $lines = explode("\n", str_replace("\n", "\n", $cell)); + $lines = explode($eol, str_replace($eol, ''.$eol, $cell)); foreach ($lines as $lineKey => $line) { if ($colspan > 1) { $line = new TableCell($line, ['colspan' => $colspan]); @@ -688,8 +703,9 @@ private function fillNextRows(array $rows, int $line): array $nbLines = $cell->getRowspan() - 1; $lines = [$cell]; if (str_contains($cell, "\n")) { - $lines = explode("\n", str_replace("\n", "\n", $cell)); - $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; + $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n"; + $lines = explode($eol, str_replace($eol, ''.$eol.'', $cell)); + $nbLines = \count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines; $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); unset($lines[0]); diff --git a/app/vendor/symfony/console/Helper/TableStyle.php b/app/vendor/symfony/console/Helper/TableStyle.php index bbad98e73..be956c109 100644 --- a/app/vendor/symfony/console/Helper/TableStyle.php +++ b/app/vendor/symfony/console/Helper/TableStyle.php @@ -88,7 +88,7 @@ public function getPaddingChar(): string * * @return $this */ - public function setHorizontalBorderChars(string $outside, string $inside = null): static + public function setHorizontalBorderChars(string $outside, ?string $inside = null): static { $this->horizontalOutsideBorderChar = $outside; $this->horizontalInsideBorderChar = $inside ?? $outside; @@ -113,7 +113,7 @@ public function setHorizontalBorderChars(string $outside, string $inside = null) * * @return $this */ - public function setVerticalBorderChars(string $outside, string $inside = null): static + public function setVerticalBorderChars(string $outside, ?string $inside = null): static { $this->verticalOutsideBorderChar = $outside; $this->verticalInsideBorderChar = $inside ?? $outside; @@ -167,7 +167,7 @@ public function getBorderChars(): array * * @return $this */ - public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): static + public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null): static { $this->crossingChar = $cross; $this->crossingTopLeftChar = $topLeft; diff --git a/app/vendor/symfony/console/Input/ArgvInput.php b/app/vendor/symfony/console/Input/ArgvInput.php index 59f9217ec..ab9f28c54 100644 --- a/app/vendor/symfony/console/Input/ArgvInput.php +++ b/app/vendor/symfony/console/Input/ArgvInput.php @@ -43,7 +43,7 @@ class ArgvInput extends Input private array $tokens; private array $parsed; - public function __construct(array $argv = null, InputDefinition $definition = null) + public function __construct(?array $argv = null, ?InputDefinition $definition = null) { $argv ??= $_SERVER['argv'] ?? []; diff --git a/app/vendor/symfony/console/Input/ArrayInput.php b/app/vendor/symfony/console/Input/ArrayInput.php index 355de61dd..c1bc914ca 100644 --- a/app/vendor/symfony/console/Input/ArrayInput.php +++ b/app/vendor/symfony/console/Input/ArrayInput.php @@ -27,7 +27,7 @@ class ArrayInput extends Input { private array $parameters; - public function __construct(array $parameters, InputDefinition $definition = null) + public function __construct(array $parameters, ?InputDefinition $definition = null) { $this->parameters = $parameters; diff --git a/app/vendor/symfony/console/Input/Input.php b/app/vendor/symfony/console/Input/Input.php index 0f5617cd1..1c21573bc 100644 --- a/app/vendor/symfony/console/Input/Input.php +++ b/app/vendor/symfony/console/Input/Input.php @@ -28,12 +28,13 @@ abstract class Input implements InputInterface, StreamableInputInterface { protected $definition; + /** @var resource */ protected $stream; protected $options = []; protected $arguments = []; protected $interactive = true; - public function __construct(InputDefinition $definition = null) + public function __construct(?InputDefinition $definition = null) { if (null === $definition) { $this->definition = new InputDefinition(); diff --git a/app/vendor/symfony/console/Input/InputArgument.php b/app/vendor/symfony/console/Input/InputArgument.php index 5cb151488..4ef79feb7 100644 --- a/app/vendor/symfony/console/Input/InputArgument.php +++ b/app/vendor/symfony/console/Input/InputArgument.php @@ -44,7 +44,7 @@ class InputArgument * * @throws InvalidArgumentException When argument mode is not valid */ - public function __construct(string $name, int $mode = null, string $description = '', string|bool|int|float|array $default = null, \Closure|array $suggestedValues = []) + public function __construct(string $name, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, \Closure|array $suggestedValues = []) { if (null === $mode) { $mode = self::OPTIONAL; @@ -95,7 +95,7 @@ public function isArray(): bool * * @throws LogicException When incorrect default value is given */ - public function setDefault(string|bool|int|float|array $default = null) + public function setDefault(string|bool|int|float|array|null $default = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Input/InputOption.php b/app/vendor/symfony/console/Input/InputOption.php index fdf88dcc2..bb533801f 100644 --- a/app/vendor/symfony/console/Input/InputOption.php +++ b/app/vendor/symfony/console/Input/InputOption.php @@ -65,7 +65,7 @@ class InputOption * * @throws InvalidArgumentException If option mode is invalid or incompatible */ - public function __construct(string $name, string|array $shortcut = null, int $mode = null, string $description = '', string|bool|int|float|array $default = null, array|\Closure $suggestedValues = []) + public function __construct(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, array|\Closure $suggestedValues = []) { if (str_starts_with($name, '--')) { $name = substr($name, 2); @@ -75,7 +75,7 @@ public function __construct(string $name, string|array $shortcut = null, int $mo throw new InvalidArgumentException('An option name cannot be empty.'); } - if (empty($shortcut)) { + if ('' === $shortcut || [] === $shortcut || false === $shortcut) { $shortcut = null; } @@ -84,10 +84,10 @@ public function __construct(string $name, string|array $shortcut = null, int $mo $shortcut = implode('|', $shortcut); } $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-')); - $shortcuts = array_filter($shortcuts); + $shortcuts = array_filter($shortcuts, 'strlen'); $shortcut = implode('|', $shortcuts); - if (empty($shortcut)) { + if ('' === $shortcut) { throw new InvalidArgumentException('An option shortcut cannot be empty.'); } } @@ -181,7 +181,7 @@ public function isNegatable(): bool /** * @return void */ - public function setDefault(string|bool|int|float|array $default = null) + public function setDefault(string|bool|int|float|array|null $default = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Messenger/RunCommandContext.php b/app/vendor/symfony/console/Messenger/RunCommandContext.php new file mode 100644 index 000000000..2ee5415c6 --- /dev/null +++ b/app/vendor/symfony/console/Messenger/RunCommandContext.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Messenger; + +/** + * @author Kevin Bond + */ +final class RunCommandContext +{ + public function __construct( + public readonly RunCommandMessage $message, + public readonly int $exitCode, + public readonly string $output, + ) { + } +} diff --git a/app/vendor/symfony/console/Messenger/RunCommandMessage.php b/app/vendor/symfony/console/Messenger/RunCommandMessage.php new file mode 100644 index 000000000..b530c438c --- /dev/null +++ b/app/vendor/symfony/console/Messenger/RunCommandMessage.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Messenger; + +use Symfony\Component\Console\Exception\RunCommandFailedException; + +/** + * @author Kevin Bond + */ +class RunCommandMessage implements \Stringable +{ + /** + * @param bool $throwOnFailure If the command has a non-zero exit code, throw {@see RunCommandFailedException} + * @param bool $catchExceptions @see Application::setCatchExceptions() + */ + public function __construct( + public readonly string $input, + public readonly bool $throwOnFailure = true, + public readonly bool $catchExceptions = false, + ) { + } + + public function __toString(): string + { + return $this->input; + } +} diff --git a/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php b/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php new file mode 100644 index 000000000..14f9c1764 --- /dev/null +++ b/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Messenger; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\RunCommandFailedException; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\BufferedOutput; + +/** + * @author Kevin Bond + */ +final class RunCommandMessageHandler +{ + public function __construct(private readonly Application $application) + { + } + + public function __invoke(RunCommandMessage $message): RunCommandContext + { + $input = new StringInput($message->input); + $output = new BufferedOutput(); + + $this->application->setCatchExceptions($message->catchExceptions); + + try { + $exitCode = $this->application->run($input, $output); + } catch (\Throwable $e) { + throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch())); + } + + if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { + throw new RunCommandFailedException(sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + } + + return new RunCommandContext($message, $exitCode, $output->fetch()); + } +} diff --git a/app/vendor/symfony/console/Output/ConsoleOutput.php b/app/vendor/symfony/console/Output/ConsoleOutput.php index c1eb7cd14..5837e74a3 100644 --- a/app/vendor/symfony/console/Output/ConsoleOutput.php +++ b/app/vendor/symfony/console/Output/ConsoleOutput.php @@ -37,7 +37,7 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ - public function __construct(int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null) + public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) { parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); diff --git a/app/vendor/symfony/console/Output/ConsoleSectionOutput.php b/app/vendor/symfony/console/Output/ConsoleSectionOutput.php index 21c4a44a8..f2d7933bb 100644 --- a/app/vendor/symfony/console/Output/ConsoleSectionOutput.php +++ b/app/vendor/symfony/console/Output/ConsoleSectionOutput.php @@ -63,7 +63,7 @@ public function setMaxHeight(int $maxHeight): void * * @return void */ - public function clear(int $lines = null) + public function clear(?int $lines = null) { if (empty($this->content) || !$this->isDecorated()) { return; diff --git a/app/vendor/symfony/console/Output/Output.php b/app/vendor/symfony/console/Output/Output.php index 3a06311a8..00f481e03 100644 --- a/app/vendor/symfony/console/Output/Output.php +++ b/app/vendor/symfony/console/Output/Output.php @@ -37,7 +37,7 @@ abstract class Output implements OutputInterface * @param bool $decorated Whether to decorate messages * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ - public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null) + public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL; $this->formatter = $formatter ?? new OutputFormatter(); diff --git a/app/vendor/symfony/console/Output/OutputInterface.php b/app/vendor/symfony/console/Output/OutputInterface.php index fb1557720..19a817901 100644 --- a/app/vendor/symfony/console/Output/OutputInterface.php +++ b/app/vendor/symfony/console/Output/OutputInterface.php @@ -54,12 +54,16 @@ public function writeln(string|iterable $messages, int $options = 0); /** * Sets the verbosity of the output. * + * @param self::VERBOSITY_* $level + * * @return void */ public function setVerbosity(int $level); /** * Gets the current verbosity of the output. + * + * @return self::VERBOSITY_* */ public function getVerbosity(): int; diff --git a/app/vendor/symfony/console/Output/StreamOutput.php b/app/vendor/symfony/console/Output/StreamOutput.php index 155066ea0..f51d03763 100644 --- a/app/vendor/symfony/console/Output/StreamOutput.php +++ b/app/vendor/symfony/console/Output/StreamOutput.php @@ -29,6 +29,7 @@ */ class StreamOutput extends Output { + /** @var resource */ private $stream; /** @@ -39,7 +40,7 @@ class StreamOutput extends Output * * @throws InvalidArgumentException When first argument is not a real stream */ - public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null) + public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) { if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) { throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); @@ -92,22 +93,33 @@ protected function doWrite(string $message, bool $newline) protected function hasColorSupport(): bool { // Follow https://no-color.org/ - if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { + if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) { return false; } - if ('Hyper' === getenv('TERM_PROGRAM')) { + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) { return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') - && @sapi_windows_vt100_support($this->stream)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM'); + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + ) { + return true; + } + + if ('dumb' === $term = (string) getenv('TERM')) { + return false; } - return stream_isatty($this->stream); + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); } } diff --git a/app/vendor/symfony/console/Output/TrimmedBufferOutput.php b/app/vendor/symfony/console/Output/TrimmedBufferOutput.php index b00445ece..23a2be8c3 100644 --- a/app/vendor/symfony/console/Output/TrimmedBufferOutput.php +++ b/app/vendor/symfony/console/Output/TrimmedBufferOutput.php @@ -24,7 +24,7 @@ class TrimmedBufferOutput extends Output private int $maxLength; private string $buffer = ''; - public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null) + public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); diff --git a/app/vendor/symfony/console/Question/ChoiceQuestion.php b/app/vendor/symfony/console/Question/ChoiceQuestion.php index e449ff683..465f3184f 100644 --- a/app/vendor/symfony/console/Question/ChoiceQuestion.php +++ b/app/vendor/symfony/console/Question/ChoiceQuestion.php @@ -26,11 +26,11 @@ class ChoiceQuestion extends Question private string $errorMessage = 'Value "%s" is invalid'; /** - * @param string $question The question to ask to the user - * @param array $choices The list of available choices - * @param mixed $default The default answer to return + * @param string $question The question to ask to the user + * @param array $choices The list of available choices + * @param string|bool|int|float|null $default The default answer to return */ - public function __construct(string $question, array $choices, mixed $default = null) + public function __construct(string $question, array $choices, string|bool|int|float|null $default = null) { if (!$choices) { throw new \LogicException('Choice question must have at least 1 choice available.'); diff --git a/app/vendor/symfony/console/Question/Question.php b/app/vendor/symfony/console/Question/Question.php index 26896bb53..94c688fa8 100644 --- a/app/vendor/symfony/console/Question/Question.php +++ b/app/vendor/symfony/console/Question/Question.php @@ -36,7 +36,7 @@ class Question * @param string $question The question to ask to the user * @param string|bool|int|float|null $default The default answer to return if the user enters nothing */ - public function __construct(string $question, string|bool|int|float $default = null) + public function __construct(string $question, string|bool|int|float|null $default = null) { $this->question = $question; $this->default = $default; @@ -175,7 +175,7 @@ public function getAutocompleterCallback(): ?callable * * @return $this */ - public function setAutocompleterCallback(callable $callback = null): static + public function setAutocompleterCallback(?callable $callback = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -194,7 +194,7 @@ public function setAutocompleterCallback(callable $callback = null): static * * @return $this */ - public function setValidator(callable $validator = null): static + public function setValidator(?callable $validator = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/README.md b/app/vendor/symfony/console/README.md index bfd488109..e9013182a 100644 --- a/app/vendor/symfony/console/README.md +++ b/app/vendor/symfony/console/README.md @@ -7,7 +7,7 @@ interfaces. Sponsor ------- -The Console component for Symfony 6.3 is [backed][1] by [Les-Tilleuls.coop][2]. +The Console component for Symfony 6.4 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, diff --git a/app/vendor/symfony/console/Resources/completion.bash b/app/vendor/symfony/console/Resources/completion.bash index 0d76eacc3..64c6a338f 100644 --- a/app/vendor/symfony/console/Resources/completion.bash +++ b/app/vendor/symfony/console/Resources/completion.bash @@ -17,7 +17,7 @@ _sf_{{ COMMAND_NAME }}() { done # Use newline as only separator to allow space in completion values - IFS=$'\n' + local IFS=$'\n' local sf_cmd="${COMP_WORDS[0]}" # for an alias, get the real script behind it diff --git a/app/vendor/symfony/console/SignalRegistry/SignalMap.php b/app/vendor/symfony/console/SignalRegistry/SignalMap.php new file mode 100644 index 000000000..2f9aa67c1 --- /dev/null +++ b/app/vendor/symfony/console/SignalRegistry/SignalMap.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\SignalRegistry; + +/** + * @author Grégoire Pineau + */ +class SignalMap +{ + private static array $map; + + public static function getSignalName(int $signal): ?string + { + if (!\extension_loaded('pcntl')) { + return null; + } + + if (!isset(self::$map)) { + $r = new \ReflectionExtension('pcntl'); + $c = $r->getConstants(); + $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_') && 'SIGBABY' !== $k, \ARRAY_FILTER_USE_KEY); + self::$map = array_flip($map); + } + + return self::$map[$signal] ?? null; + } +} diff --git a/app/vendor/symfony/console/SingleCommandApplication.php b/app/vendor/symfony/console/SingleCommandApplication.php index 4f0b5ba3c..ff1c17247 100644 --- a/app/vendor/symfony/console/SingleCommandApplication.php +++ b/app/vendor/symfony/console/SingleCommandApplication.php @@ -46,7 +46,7 @@ public function setAutoExit(bool $autoExit): static return $this; } - public function run(InputInterface $input = null, OutputInterface $output = null): int + public function run(?InputInterface $input = null, ?OutputInterface $output = null): int { if ($this->running) { return parent::run($input, $output); diff --git a/app/vendor/symfony/console/Style/StyleInterface.php b/app/vendor/symfony/console/Style/StyleInterface.php index e25a65bd2..6bced158a 100644 --- a/app/vendor/symfony/console/Style/StyleInterface.php +++ b/app/vendor/symfony/console/Style/StyleInterface.php @@ -91,12 +91,12 @@ public function table(array $headers, array $rows); /** * Asks a question. */ - public function ask(string $question, string $default = null, callable $validator = null): mixed; + public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed; /** * Asks a question with the user input hidden. */ - public function askHidden(string $question, callable $validator = null): mixed; + public function askHidden(string $question, ?callable $validator = null): mixed; /** * Asks for confirmation. diff --git a/app/vendor/symfony/console/Style/SymfonyStyle.php b/app/vendor/symfony/console/Style/SymfonyStyle.php index cecce6c01..03bda8784 100644 --- a/app/vendor/symfony/console/Style/SymfonyStyle.php +++ b/app/vendor/symfony/console/Style/SymfonyStyle.php @@ -63,7 +63,7 @@ public function __construct(InputInterface $input, OutputInterface $output) * * @return void */ - public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) + public function block(string|array $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) { $messages = \is_array($messages) ? array_values($messages) : [$messages]; @@ -249,7 +249,7 @@ public function definitionList(string|array|TableSeparator ...$list) $this->horizontalTable($headers, [$row]); } - public function ask(string $question, string $default = null, callable $validator = null): mixed + public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed { $question = new Question($question, $default); $question->setValidator($validator); @@ -257,7 +257,7 @@ public function ask(string $question, string $default = null, callable $validato return $this->askQuestion($question); } - public function askHidden(string $question, callable $validator = null): mixed + public function askHidden(string $question, ?callable $validator = null): mixed { $question = new Question($question); @@ -327,8 +327,16 @@ public function createProgressBar(int $max = 0): ProgressBar /** * @see ProgressBar::iterate() + * + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable */ - public function progressIterate(iterable $iterable, int $max = null): iterable + public function progressIterate(iterable $iterable, ?int $max = null): iterable { yield from $this->createProgressBar()->iterate($iterable, $max); @@ -448,7 +456,7 @@ private function writeBuffer(string $message, bool $newLine, int $type): void $this->bufferedOutput->write($message, $newLine, $type); } - private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array + private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array { $indentLength = 0; $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix)); diff --git a/app/vendor/symfony/console/Terminal.php b/app/vendor/symfony/console/Terminal.php index 3eda0376b..f094adedc 100644 --- a/app/vendor/symfony/console/Terminal.php +++ b/app/vendor/symfony/console/Terminal.php @@ -217,8 +217,7 @@ private static function readFromProcess(string|array $command): ?string $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0; - $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]); - if (!\is_resource($process)) { + if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true])) { return null; } diff --git a/app/vendor/symfony/console/Tester/CommandCompletionTester.php b/app/vendor/symfony/console/Tester/CommandCompletionTester.php index ade732752..a90fe52ef 100644 --- a/app/vendor/symfony/console/Tester/CommandCompletionTester.php +++ b/app/vendor/symfony/console/Tester/CommandCompletionTester.php @@ -22,7 +22,7 @@ */ class CommandCompletionTester { - private $command; + private Command $command; public function __construct(Command $command) { diff --git a/app/vendor/symfony/console/Tester/TesterTrait.php b/app/vendor/symfony/console/Tester/TesterTrait.php index 497b8c8c7..1ab7a70aa 100644 --- a/app/vendor/symfony/console/Tester/TesterTrait.php +++ b/app/vendor/symfony/console/Tester/TesterTrait.php @@ -130,7 +130,7 @@ public function setInputs(array $inputs): static */ private function initOutput(array $options): void { - $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; + $this->captureStreamsIndependently = $options['capture_stderr_separately'] ?? false; if (!$this->captureStreamsIndependently) { $this->output = new StreamOutput(fopen('php://memory', 'w', false)); if (isset($options['decorated'])) { diff --git a/app/vendor/symfony/console/composer.json b/app/vendor/symfony/console/composer.json index c34421299..1610f7341 100644 --- a/app/vendor/symfony/console/composer.json +++ b/app/vendor/symfony/console/composer.json @@ -20,15 +20,19 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0" + "symfony/string": "^5.4|^6.0|^7.0" }, "require-dev": { - "symfony/config": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/lock": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", "psr/log": "^1|^2|^3" }, "provide": { diff --git a/app/vendor/symfony/deprecation-contracts/composer.json b/app/vendor/symfony/deprecation-contracts/composer.json index c6d02d874..ceb6c0796 100644 --- a/app/vendor/symfony/deprecation-contracts/composer.json +++ b/app/vendor/symfony/deprecation-contracts/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/app/vendor/symfony/filesystem/CHANGELOG.md b/app/vendor/symfony/filesystem/CHANGELOG.md index fcb7170ca..80818d1b5 100644 --- a/app/vendor/symfony/filesystem/CHANGELOG.md +++ b/app/vendor/symfony/filesystem/CHANGELOG.md @@ -1,6 +1,16 @@ CHANGELOG ========= +7.1 +--- + + * Add the `Filesystem::readFile()` method + +7.0 +--- + + * Add argument `$lock` to `Filesystem::appendToFile()` + 5.4 --- diff --git a/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php b/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php index 48b640809..d0d27977d 100644 --- a/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php +++ b/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php @@ -19,13 +19,13 @@ */ class FileNotFoundException extends IOException { - public function __construct(string $message = null, int $code = 0, \Throwable $previous = null, string $path = null) + public function __construct(?string $message = null, int $code = 0, ?\Throwable $previous = null, ?string $path = null) { if (null === $message) { if (null === $path) { $message = 'File could not be found.'; } else { - $message = sprintf('File "%s" could not be found.', $path); + $message = \sprintf('File "%s" could not be found.', $path); } } diff --git a/app/vendor/symfony/filesystem/Exception/IOException.php b/app/vendor/symfony/filesystem/Exception/IOException.php index a3c544553..46ab8b4a5 100644 --- a/app/vendor/symfony/filesystem/Exception/IOException.php +++ b/app/vendor/symfony/filesystem/Exception/IOException.php @@ -20,12 +20,12 @@ */ class IOException extends \RuntimeException implements IOExceptionInterface { - private ?string $path; - - public function __construct(string $message, int $code = 0, \Throwable $previous = null, string $path = null) - { - $this->path = $path; - + public function __construct( + string $message, + int $code = 0, + ?\Throwable $previous = null, + private ?string $path = null, + ) { parent::__construct($message, $code, $previous); } diff --git a/app/vendor/symfony/filesystem/Filesystem.php b/app/vendor/symfony/filesystem/Filesystem.php index a379ce186..f97c8b2fe 100644 --- a/app/vendor/symfony/filesystem/Filesystem.php +++ b/app/vendor/symfony/filesystem/Filesystem.php @@ -22,7 +22,7 @@ */ class Filesystem { - private static $lastError; + private static ?string $lastError = null; /** * Copies a file. @@ -31,34 +31,32 @@ class Filesystem * If the target file is newer, it is overwritten only when the * $overwriteNewerFiles option is set to true. * - * @return void - * * @throws FileNotFoundException When originFile doesn't exist * @throws IOException When copy fails */ - public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = false) + public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = false): void { $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://'); if ($originIsLocal && !is_file($originFile)) { - throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile); + throw new FileNotFoundException(\sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile); } $this->mkdir(\dirname($targetFile)); $doCopy = true; - if (!$overwriteNewerFiles && null === parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) { + if (!$overwriteNewerFiles && !parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) { $doCopy = filemtime($originFile) > filemtime($targetFile); } if ($doCopy) { // https://bugs.php.net/64634 if (!$source = self::box('fopen', $originFile, 'r')) { - throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); } // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default if (!$target = self::box('fopen', $targetFile, 'w', false, stream_context_create(['ftp' => ['overwrite' => true]]))) { - throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); } $bytesCopied = stream_copy_to_stream($source, $target); @@ -67,15 +65,18 @@ public function copy(string $originFile, string $targetFile, bool $overwriteNewe unset($source, $target); if (!is_file($targetFile)) { - throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile); } if ($originIsLocal) { // Like `cp`, preserve executable permission bits self::box('chmod', $targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111)); + // Like `cp`, preserve the file modification time + self::box('touch', $targetFile, filemtime($originFile)); + if ($bytesCopied !== $bytesOrigin = filesize($originFile)) { - throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile); } } } @@ -84,11 +85,9 @@ public function copy(string $originFile, string $targetFile, bool $overwriteNewe /** * Creates a directory recursively. * - * @return void - * * @throws IOException On any directory creation failure */ - public function mkdir(string|iterable $dirs, int $mode = 0777) + public function mkdir(string|iterable $dirs, int $mode = 0777): void { foreach ($this->toIterable($dirs) as $dir) { if (is_dir($dir)) { @@ -96,7 +95,7 @@ public function mkdir(string|iterable $dirs, int $mode = 0777) } if (!self::box('mkdir', $dir, $mode, true) && !is_dir($dir)) { - throw new IOException(sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir); + throw new IOException(\sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir); } } } @@ -110,7 +109,7 @@ public function exists(string|iterable $files): bool foreach ($this->toIterable($files) as $file) { if (\strlen($file) > $maxPathLength) { - throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file); + throw new IOException(\sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file); } if (!file_exists($file)) { @@ -127,15 +126,13 @@ public function exists(string|iterable $files): bool * @param int|null $time The touch time as a Unix timestamp, if not supplied the current system time is used * @param int|null $atime The access time as a Unix timestamp, if not supplied the current system time is used * - * @return void - * * @throws IOException When touch fails */ - public function touch(string|iterable $files, int $time = null, int $atime = null) + public function touch(string|iterable $files, ?int $time = null, ?int $atime = null): void { foreach ($this->toIterable($files) as $file) { if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) { - throw new IOException(sprintf('Failed to touch "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to touch "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -143,11 +140,9 @@ public function touch(string|iterable $files, int $time = null, int $atime = nul /** * Removes files or directories. * - * @return void - * * @throws IOException When removal fails */ - public function remove(string|iterable $files) + public function remove(string|iterable $files): void { if ($files instanceof \Traversable) { $files = iterator_to_array($files, false); @@ -165,11 +160,11 @@ private static function doRemove(array $files, bool $isRecursive): void if (is_link($file)) { // See https://bugs.php.net/52176 if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) { - throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError); + throw new IOException(\sprintf('Failed to remove symlink "%s": ', $file).self::$lastError); } } elseif (is_dir($file)) { if (!$isRecursive) { - $tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-_')); + $tmpName = \dirname(realpath($file)).'/.!'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-!')); if (file_exists($tmpName)) { try { @@ -196,10 +191,10 @@ private static function doRemove(array $files, bool $isRecursive): void $file = $origFile; } - throw new IOException(sprintf('Failed to remove directory "%s": ', $file).$lastError); + throw new IOException(\sprintf('Failed to remove directory "%s": ', $file).$lastError); } - } elseif (!self::box('unlink', $file) && (str_contains(self::$lastError, 'Permission denied') || file_exists($file))) { - throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError); + } elseif (!self::box('unlink', $file) && ((self::$lastError && str_contains(self::$lastError, 'Permission denied')) || file_exists($file))) { + throw new IOException(\sprintf('Failed to remove file "%s": ', $file).self::$lastError); } } } @@ -211,15 +206,13 @@ private static function doRemove(array $files, bool $isRecursive): void * @param int $umask The mode mask (octal) * @param bool $recursive Whether change the mod recursively or not * - * @return void - * * @throws IOException When the change fails */ - public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool $recursive = false) + public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool $recursive = false): void { foreach ($this->toIterable($files) as $file) { if (!self::box('chmod', $file, $mode & ~$umask)) { - throw new IOException(sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file); } if ($recursive && is_dir($file) && !is_link($file)) { $this->chmod(new \FilesystemIterator($file), $mode, $umask, true); @@ -230,14 +223,16 @@ public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool /** * Change the owner of an array of files or directories. * + * This method always throws on Windows, as the underlying PHP function is not supported. + * + * @see https://www.php.net/chown + * * @param string|int $user A user name or number * @param bool $recursive Whether change the owner recursively or not * - * @return void - * * @throws IOException When the change fails */ - public function chown(string|iterable $files, string|int $user, bool $recursive = false) + public function chown(string|iterable $files, string|int $user, bool $recursive = false): void { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { @@ -245,11 +240,11 @@ public function chown(string|iterable $files, string|int $user, bool $recursive } if (is_link($file) && \function_exists('lchown')) { if (!self::box('lchown', $file, $user)) { - throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); } } else { if (!self::box('chown', $file, $user)) { - throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -258,14 +253,16 @@ public function chown(string|iterable $files, string|int $user, bool $recursive /** * Change the group of an array of files or directories. * + * This method always throws on Windows, as the underlying PHP function is not supported. + * + * @see https://www.php.net/chgrp + * * @param string|int $group A group name or number * @param bool $recursive Whether change the group recursively or not * - * @return void - * * @throws IOException When the change fails */ - public function chgrp(string|iterable $files, string|int $group, bool $recursive = false) + public function chgrp(string|iterable $files, string|int $group, bool $recursive = false): void { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { @@ -273,11 +270,11 @@ public function chgrp(string|iterable $files, string|int $group, bool $recursive } if (is_link($file) && \function_exists('lchgrp')) { if (!self::box('lchgrp', $file, $group)) { - throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); } } else { if (!self::box('chgrp', $file, $group)) { - throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -286,16 +283,14 @@ public function chgrp(string|iterable $files, string|int $group, bool $recursive /** * Renames a file or a directory. * - * @return void - * * @throws IOException When target file or directory already exists * @throws IOException When origin cannot be renamed */ - public function rename(string $origin, string $target, bool $overwrite = false) + public function rename(string $origin, string $target, bool $overwrite = false): void { // we check that target does not exist if (!$overwrite && $this->isReadable($target)) { - throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); + throw new IOException(\sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); } if (!self::box('rename', $origin, $target)) { @@ -306,7 +301,7 @@ public function rename(string $origin, string $target, bool $overwrite = false) return; } - throw new IOException(sprintf('Cannot rename "%s" to "%s": ', $origin, $target).self::$lastError, 0, null, $target); + throw new IOException(\sprintf('Cannot rename "%s" to "%s": ', $origin, $target).self::$lastError, 0, null, $target); } } @@ -320,7 +315,7 @@ private function isReadable(string $filename): bool $maxPathLength = \PHP_MAXPATHLEN - 2; if (\strlen($filename) > $maxPathLength) { - throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename); + throw new IOException(\sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename); } return is_readable($filename); @@ -329,11 +324,9 @@ private function isReadable(string $filename): bool /** * Creates a symbolic link or copy a directory. * - * @return void - * * @throws IOException When symlink fails */ - public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false) + public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false): void { self::assertFunctionExists('symlink'); @@ -367,12 +360,10 @@ public function symlink(string $originDir, string $targetDir, bool $copyOnWindow * * @param string|string[] $targetFiles The target file(s) * - * @return void - * * @throws FileNotFoundException When original file is missing or not a file * @throws IOException When link fails, including if link already exists */ - public function hardlink(string $originFile, string|iterable $targetFiles) + public function hardlink(string $originFile, string|iterable $targetFiles): void { self::assertFunctionExists('link'); @@ -381,7 +372,7 @@ public function hardlink(string $originFile, string|iterable $targetFiles) } if (!is_file($originFile)) { - throw new FileNotFoundException(sprintf('Origin file "%s" is not a file.', $originFile)); + throw new FileNotFoundException(\sprintf('Origin file "%s" is not a file.', $originFile)); } foreach ($this->toIterable($targetFiles) as $targetFile) { @@ -405,10 +396,10 @@ private function linkException(string $origin, string $target, string $linkType) { if (self::$lastError) { if ('\\' === \DIRECTORY_SEPARATOR && str_contains(self::$lastError, 'error code(1314)')) { - throw new IOException(sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target); + throw new IOException(\sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target); } } - throw new IOException(sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target).self::$lastError, 0, null, $target); + throw new IOException(\sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target).self::$lastError, 0, null, $target); } /** @@ -445,11 +436,11 @@ public function readlink(string $path, bool $canonicalize = false): ?string public function makePathRelative(string $endPath, string $startPath): string { if (!$this->isAbsolutePath($startPath)) { - throw new InvalidArgumentException(sprintf('The start path "%s" is not absolute.', $startPath)); + throw new InvalidArgumentException(\sprintf('The start path "%s" is not absolute.', $startPath)); } if (!$this->isAbsolutePath($endPath)) { - throw new InvalidArgumentException(sprintf('The end path "%s" is not absolute.', $endPath)); + throw new InvalidArgumentException(\sprintf('The end path "%s" is not absolute.', $endPath)); } // Normalize separators on Windows @@ -526,18 +517,16 @@ public function makePathRelative(string $endPath, string $startPath): string * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) * - * @return void - * * @throws IOException When file type is unknown */ - public function mirror(string $originDir, string $targetDir, \Traversable $iterator = null, array $options = []) + public function mirror(string $originDir, string $targetDir, ?\Traversable $iterator = null, array $options = []): void { $targetDir = rtrim($targetDir, '/\\'); $originDir = rtrim($originDir, '/\\'); $originDirLen = \strlen($originDir); if (!$this->exists($originDir)) { - throw new IOException(sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir); + throw new IOException(\sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir); } // Iterate in destination folder to remove obsolete entries @@ -581,7 +570,7 @@ public function mirror(string $originDir, string $targetDir, \Traversable $itera } elseif (is_file($file)) { $this->copy($file, $target, $options['override'] ?? false); } else { - throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); + throw new IOException(\sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); } } } @@ -630,7 +619,7 @@ public function tempnam(string $dir, string $prefix, string $suffix = ''): strin // Loop until we create a valid temp file or have reached 10 attempts for ($i = 0; $i < 10; ++$i) { // Create a unique filename - $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true).$suffix; + $tmpFile = $dir.'/'.$prefix.bin2hex(random_bytes(4)).$suffix; // Use fopen instead of file_exists as some streams do not support stat // Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability @@ -652,14 +641,12 @@ public function tempnam(string $dir, string $prefix, string $suffix = ''): strin * * @param string|resource $content The data to write into the file * - * @return void - * * @throws IOException if the file cannot be written to */ - public function dumpFile(string $filename, $content) + public function dumpFile(string $filename, $content): void { if (\is_array($content)) { - throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); + throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); } $dir = \dirname($filename); @@ -680,14 +667,18 @@ public function dumpFile(string $filename, $content) try { if (false === self::box('file_put_contents', $tmpFile, $content)) { - throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); + throw new IOException(\sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); } - self::box('chmod', $tmpFile, file_exists($filename) ? fileperms($filename) : 0666 & ~umask()); + self::box('chmod', $tmpFile, self::box('fileperms', $filename) ?: 0666 & ~umask()); $this->rename($tmpFile, $filename, true); } finally { if (file_exists($tmpFile)) { + if ('\\' === \DIRECTORY_SEPARATOR && !is_writable($tmpFile)) { + self::box('chmod', $tmpFile, self::box('fileperms', $tmpFile) | 0200); + } + self::box('unlink', $tmpFile); } } @@ -699,14 +690,12 @@ public function dumpFile(string $filename, $content) * @param string|resource $content The content to append * @param bool $lock Whether the file should be locked when writing to it * - * @return void - * * @throws IOException If the file is not writable */ - public function appendToFile(string $filename, $content/* , bool $lock = false */) + public function appendToFile(string $filename, $content, bool $lock = false): void { if (\is_array($content)) { - throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); + throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); } $dir = \dirname($filename); @@ -715,13 +704,30 @@ public function appendToFile(string $filename, $content/* , bool $lock = false * $this->mkdir($dir); } - $lock = \func_num_args() > 2 && func_get_arg(2); - if (false === self::box('file_put_contents', $filename, $content, \FILE_APPEND | ($lock ? \LOCK_EX : 0))) { - throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); + throw new IOException(\sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); } } + /** + * Returns the content of a file as a string. + * + * @throws IOException If the file cannot be read + */ + public function readFile(string $filename): string + { + if (is_dir($filename)) { + throw new IOException(\sprintf('Failed to read file "%s": File is a directory.', $filename)); + } + + $content = self::box('file_get_contents', $filename); + if (false === $content) { + throw new IOException(\sprintf('Failed to read file "%s": ', $filename).self::$lastError, 0, null, $filename); + } + + return $content; + } + private function toIterable(string|iterable $files): iterable { return is_iterable($files) ? $files : [$files]; @@ -740,7 +746,7 @@ private function getSchemeAndHierarchy(string $filename): array private static function assertFunctionExists(string $func): void { if (!\function_exists($func)) { - throw new IOException(sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func)); + throw new IOException(\sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func)); } } @@ -749,7 +755,7 @@ private static function box(string $func, mixed ...$args): mixed self::assertFunctionExists($func); self::$lastError = null; - set_error_handler(__CLASS__.'::handleError'); + set_error_handler(self::handleError(...)); try { return $func(...$args); } finally { diff --git a/app/vendor/symfony/filesystem/Path.php b/app/vendor/symfony/filesystem/Path.php index 8ddbac8f4..2f2e87903 100644 --- a/app/vendor/symfony/filesystem/Path.php +++ b/app/vendor/symfony/filesystem/Path.php @@ -42,12 +42,9 @@ final class Path * * @var array */ - private static $buffer = []; + private static array $buffer = []; - /** - * @var int - */ - private static $bufferSize = 0; + private static int $bufferSize = 0; /** * Canonicalizes the given path. @@ -257,7 +254,7 @@ public static function getRoot(string $path): string * @param string|null $extension if specified, only that extension is cut * off (may contain leading dot) */ - public static function getFilenameWithoutExtension(string $path, string $extension = null): string + public static function getFilenameWithoutExtension(string $path, ?string $extension = null): string { if ('' === $path) { return ''; @@ -349,13 +346,13 @@ public static function changeExtension(string $path, string $extension): string $extension = ltrim($extension, '.'); // No extension for paths - if ('/' === substr($path, -1)) { + if (str_ends_with($path, '/')) { return $path; } // No actual extension in path - if (empty($actualExtension)) { - return $path.('.' === substr($path, -1) ? '' : '.').$extension; + if (!$actualExtension) { + return $path.(str_ends_with($path, '.') ? '' : '.').$extension; } return substr($path, 0, -\strlen($actualExtension)).$extension; @@ -368,7 +365,7 @@ public static function isAbsolute(string $path): bool } // Strip scheme - if (false !== $schemeSeparatorPosition = strpos($path, '://')) { + if (false !== ($schemeSeparatorPosition = strpos($path, '://')) && 1 !== $schemeSeparatorPosition) { $path = substr($path, $schemeSeparatorPosition + 3); } @@ -440,11 +437,11 @@ public static function isRelative(string $path): bool public static function makeAbsolute(string $path, string $basePath): string { if ('' === $basePath) { - throw new InvalidArgumentException(sprintf('The base path must be a non-empty string. Got: "%s".', $basePath)); + throw new InvalidArgumentException(\sprintf('The base path must be a non-empty string. Got: "%s".', $basePath)); } if (!self::isAbsolute($basePath)) { - throw new InvalidArgumentException(sprintf('The base path "%s" is not an absolute path.', $basePath)); + throw new InvalidArgumentException(\sprintf('The base path "%s" is not an absolute path.', $basePath)); } if (self::isAbsolute($path)) { @@ -534,12 +531,12 @@ public static function makeRelative(string $path, string $basePath): string // If the passed path is absolute, but the base path is not, we // cannot generate a relative path if ('' !== $root && '' === $baseRoot) { - throw new InvalidArgumentException(sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath)); + throw new InvalidArgumentException(\sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath)); } // Fail if the roots of the two paths are different if ($baseRoot && $root !== $baseRoot) { - throw new InvalidArgumentException(sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot)); + throw new InvalidArgumentException(\sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot)); } if ('' === $relativeBasePath) { @@ -671,7 +668,7 @@ public static function join(string ...$paths): string } // Only add slash if previous part didn't end with '/' or '\' - if (!\in_array(substr($finalPath, -1), ['/', '\\'])) { + if (!\in_array(substr($finalPath, -1), ['/', '\\'], true)) { $finalPath .= '/'; } diff --git a/app/vendor/symfony/filesystem/composer.json b/app/vendor/symfony/filesystem/composer.json index 10a7a531c..c781e55b1 100644 --- a/app/vendor/symfony/filesystem/composer.json +++ b/app/vendor/symfony/filesystem/composer.json @@ -16,10 +16,13 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ diff --git a/app/vendor/symfony/finder/CHANGELOG.md b/app/vendor/symfony/finder/CHANGELOG.md index 1a12afe65..e83830247 100644 --- a/app/vendor/symfony/finder/CHANGELOG.md +++ b/app/vendor/symfony/finder/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.4 +--- + + * Add early directory pruning to `Finder::filter()` + 6.2 --- diff --git a/app/vendor/symfony/finder/Comparator/Comparator.php b/app/vendor/symfony/finder/Comparator/Comparator.php index bd6858347..41c02ac69 100644 --- a/app/vendor/symfony/finder/Comparator/Comparator.php +++ b/app/vendor/symfony/finder/Comparator/Comparator.php @@ -16,16 +16,16 @@ */ class Comparator { - private string $target; private string $operator; - public function __construct(string $target, string $operator = '==') - { + public function __construct( + private string $target, + string $operator = '==', + ) { if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { - throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator)); + throw new \InvalidArgumentException(\sprintf('Invalid operator "%s".', $operator)); } - $this->target = $target; $this->operator = $operator; } diff --git a/app/vendor/symfony/finder/Comparator/DateComparator.php b/app/vendor/symfony/finder/Comparator/DateComparator.php index e0c523d05..bcf93cfb6 100644 --- a/app/vendor/symfony/finder/Comparator/DateComparator.php +++ b/app/vendor/symfony/finder/Comparator/DateComparator.php @@ -26,17 +26,17 @@ class DateComparator extends Comparator public function __construct(string $test) { if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) { - throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test)); + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a date test.', $test)); } try { $date = new \DateTimeImmutable($matches[2]); $target = $date->format('U'); } catch (\Exception) { - throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2])); + throw new \InvalidArgumentException(\sprintf('"%s" is not a valid date.', $matches[2])); } - $operator = $matches[1] ?? '=='; + $operator = $matches[1] ?: '=='; if ('since' === $operator || 'after' === $operator) { $operator = '>'; } diff --git a/app/vendor/symfony/finder/Comparator/NumberComparator.php b/app/vendor/symfony/finder/Comparator/NumberComparator.php index dd3082077..0ec0049ff 100644 --- a/app/vendor/symfony/finder/Comparator/NumberComparator.php +++ b/app/vendor/symfony/finder/Comparator/NumberComparator.php @@ -19,7 +19,7 @@ * magnitudes. * * The target value may use magnitudes of kilobytes (k, ki), - * megabytes (m, mi), or gigabytes (g, gi). Those suffixed + * megabytes (m, mi), or gigabytes (g, gi). Those suffixed * with an i use the appropriate 2**n version in accordance with the * IEC standard: http://physics.nist.gov/cuu/Units/binary.html * @@ -42,12 +42,12 @@ class NumberComparator extends Comparator public function __construct(?string $test) { if (null === $test || !preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) { - throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null')); + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null')); } $target = $matches[2]; if (!is_numeric($target)) { - throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target)); + throw new \InvalidArgumentException(\sprintf('Invalid number "%s".', $target)); } if (isset($matches[3])) { // magnitude diff --git a/app/vendor/symfony/finder/Finder.php b/app/vendor/symfony/finder/Finder.php index a3bf9a1a7..78673af66 100644 --- a/app/vendor/symfony/finder/Finder.php +++ b/app/vendor/symfony/finder/Finder.php @@ -50,6 +50,7 @@ class Finder implements \IteratorAggregate, \Countable private array $notNames = []; private array $exclude = []; private array $filters = []; + private array $pruneFilters = []; private array $depths = []; private array $sizes = []; private bool $followLinks = false; @@ -123,7 +124,7 @@ public function files(): static public function depth(string|int|array $levels): static { foreach ((array) $levels as $level) { - $this->depths[] = new Comparator\NumberComparator($level); + $this->depths[] = new NumberComparator($level); } return $this; @@ -151,7 +152,7 @@ public function depth(string|int|array $levels): static public function date(string|array $dates): static { foreach ((array) $dates as $date) { - $this->dates[] = new Comparator\DateComparator($date); + $this->dates[] = new DateComparator($date); } return $this; @@ -306,7 +307,7 @@ public function notPath(string|array $patterns): static public function size(string|int|array $sizes): static { foreach ((array) $sizes as $size) { - $this->sizes[] = new Comparator\NumberComparator($size); + $this->sizes[] = new NumberComparator($size); } return $this; @@ -396,10 +397,8 @@ public function ignoreVCSIgnored(bool $ignoreVCSIgnored): static * @see ignoreVCS() * * @param string|string[] $pattern VCS patterns to ignore - * - * @return void */ - public static function addVCSPattern(string|array $pattern) + public static function addVCSPattern(string|array $pattern): void { foreach ((array) $pattern as $p) { self::$vcsPatterns[] = $p; @@ -437,7 +436,7 @@ public function sort(\Closure $closure): static */ public function sortByExtension(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_EXTENSION; + $this->sort = SortableIterator::SORT_BY_EXTENSION; return $this; } @@ -453,7 +452,7 @@ public function sortByExtension(): static */ public function sortByName(bool $useNaturalSort = false): static { - $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME; + $this->sort = $useNaturalSort ? SortableIterator::SORT_BY_NAME_NATURAL : SortableIterator::SORT_BY_NAME; return $this; } @@ -469,7 +468,7 @@ public function sortByName(bool $useNaturalSort = false): static */ public function sortByCaseInsensitiveName(bool $useNaturalSort = false): static { - $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE : Iterator\SortableIterator::SORT_BY_NAME_CASE_INSENSITIVE; + $this->sort = $useNaturalSort ? SortableIterator::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE : SortableIterator::SORT_BY_NAME_CASE_INSENSITIVE; return $this; } @@ -485,7 +484,7 @@ public function sortByCaseInsensitiveName(bool $useNaturalSort = false): static */ public function sortBySize(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_SIZE; + $this->sort = SortableIterator::SORT_BY_SIZE; return $this; } @@ -501,7 +500,7 @@ public function sortBySize(): static */ public function sortByType(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_TYPE; + $this->sort = SortableIterator::SORT_BY_TYPE; return $this; } @@ -519,7 +518,7 @@ public function sortByType(): static */ public function sortByAccessedTime(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME; + $this->sort = SortableIterator::SORT_BY_ACCESSED_TIME; return $this; } @@ -551,7 +550,7 @@ public function reverseSorting(): static */ public function sortByChangedTime(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME; + $this->sort = SortableIterator::SORT_BY_CHANGED_TIME; return $this; } @@ -569,7 +568,7 @@ public function sortByChangedTime(): static */ public function sortByModifiedTime(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME; + $this->sort = SortableIterator::SORT_BY_MODIFIED_TIME; return $this; } @@ -580,14 +579,21 @@ public function sortByModifiedTime(): static * The anonymous function receives a \SplFileInfo and must return false * to remove files. * + * @param \Closure(SplFileInfo): bool $closure + * @param bool $prune Whether to skip traversing directories further + * * @return $this * * @see CustomFilterIterator */ - public function filter(\Closure $closure): static + public function filter(\Closure $closure, bool $prune = false): static { $this->filters[] = $closure; + if ($prune) { + $this->pruneFilters[] = $closure; + } + return $this; } @@ -637,7 +643,7 @@ public function in(string|array $dirs): static sort($glob); $resolvedDirs[] = array_map($this->normalizeDir(...), $glob); } else { - throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir)); + throw new DirectoryNotFoundException(\sprintf('The "%s" directory does not exist.', $dir)); } } @@ -665,7 +671,7 @@ public function getIterator(): \Iterator $iterator = $this->searchInDirectory($this->dirs[0]); if ($this->sort || $this->reverseSorting) { - $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); + $iterator = (new SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); } return $iterator; @@ -681,7 +687,7 @@ public function getIterator(): \Iterator } if ($this->sort || $this->reverseSorting) { - $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); + $iterator = (new SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); } return $iterator; @@ -693,8 +699,6 @@ public function getIterator(): \Iterator * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. * * @return $this - * - * @throws \InvalidArgumentException when the given argument is not iterable */ public function append(iterable $iterator): static { @@ -702,15 +706,13 @@ public function append(iterable $iterator): static $this->iterators[] = $iterator->getIterator(); } elseif ($iterator instanceof \Iterator) { $this->iterators[] = $iterator; - } elseif (is_iterable($iterator)) { + } else { $it = new \ArrayIterator(); foreach ($iterator as $file) { $file = $file instanceof \SplFileInfo ? $file : new \SplFileInfo($file); $it[$file->getPathname()] = $file; } $this->iterators[] = $it; - } else { - throw new \InvalidArgumentException('Finder::append() method wrong argument type.'); } return $this; @@ -741,6 +743,10 @@ private function searchInDirectory(string $dir): \Iterator $exclude = $this->exclude; $notPaths = $this->notPaths; + if ($this->pruneFilters) { + $exclude = array_merge($exclude, $this->pruneFilters); + } + if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) { $exclude = array_merge($exclude, self::$vcsPatterns); } @@ -780,13 +786,13 @@ private function searchInDirectory(string $dir): \Iterator $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); if ($exclude) { - $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude); + $iterator = new ExcludeDirectoryFilterIterator($iterator, $exclude); } $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); if ($minDepth > 0 || $maxDepth < \PHP_INT_MAX) { - $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); + $iterator = new DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); } if ($this->mode) { @@ -794,23 +800,23 @@ private function searchInDirectory(string $dir): \Iterator } if ($this->names || $this->notNames) { - $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames); + $iterator = new FilenameFilterIterator($iterator, $this->names, $this->notNames); } if ($this->contains || $this->notContains) { - $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); + $iterator = new FilecontentFilterIterator($iterator, $this->contains, $this->notContains); } if ($this->sizes) { - $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes); + $iterator = new SizeRangeFilterIterator($iterator, $this->sizes); } if ($this->dates) { - $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates); + $iterator = new DateRangeFilterIterator($iterator, $this->dates); } if ($this->filters) { - $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); + $iterator = new CustomFilterIterator($iterator, $this->filters); } if ($this->paths || $notPaths) { diff --git a/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php b/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php index 699b1acbf..ebbc76ec7 100644 --- a/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -27,12 +27,15 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi /** @var \Iterator */ private \Iterator $iterator; private bool $isRecursive; + /** @var array */ private array $excludedDirs = []; private ?string $excludedPattern = null; + /** @var list */ + private array $pruneFilters = []; /** - * @param \Iterator $iterator The Iterator to filter - * @param string[] $directories An array of directories to exclude + * @param \Iterator $iterator The Iterator to filter + * @param list $directories An array of directories to exclude */ public function __construct(\Iterator $iterator, array $directories) { @@ -40,6 +43,16 @@ public function __construct(\Iterator $iterator, array $directories) $this->isRecursive = $iterator instanceof \RecursiveIterator; $patterns = []; foreach ($directories as $directory) { + if (!\is_string($directory)) { + if (!\is_callable($directory)) { + throw new \InvalidArgumentException('Invalid PHP callback.'); + } + + $this->pruneFilters[] = $directory; + + continue; + } + $directory = rtrim($directory, '/'); if (!$this->isRecursive || str_contains($directory, '/')) { $patterns[] = preg_quote($directory, '#'); @@ -70,6 +83,14 @@ public function accept(): bool return !preg_match($this->excludedPattern, $path); } + if ($this->pruneFilters && $this->hasChildren()) { + foreach ($this->pruneFilters as $pruneFilter) { + if (!$pruneFilter($this->current())) { + return false; + } + } + } + return true; } diff --git a/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php b/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php index 21303781e..0d4a5fd36 100644 --- a/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php @@ -23,16 +23,14 @@ class FileTypeFilterIterator extends \FilterIterator public const ONLY_FILES = 1; public const ONLY_DIRECTORIES = 2; - private int $mode; - /** * @param \Iterator $iterator The Iterator to filter * @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES) */ - public function __construct(\Iterator $iterator, int $mode) - { - $this->mode = $mode; - + public function __construct( + \Iterator $iterator, + private int $mode, + ) { parent::__construct($iterator); } diff --git a/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php b/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php index 82a9df301..3450c49d4 100644 --- a/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php @@ -23,8 +23,8 @@ */ abstract class MultiplePcreFilterIterator extends \FilterIterator { - protected $matchRegexps = []; - protected $noMatchRegexps = []; + protected array $matchRegexps = []; + protected array $noMatchRegexps = []; /** * @param \Iterator $iterator The Iterator to filter @@ -80,11 +80,7 @@ protected function isAccepted(string $string): bool */ protected function isRegex(string $str): bool { - $availableModifiers = 'imsxuADU'; - - if (\PHP_VERSION_ID >= 80200) { - $availableModifiers .= 'n'; - } + $availableModifiers = 'imsxuADUn'; if (preg_match('/^(.{3,}?)['.$availableModifiers.']*$/', $str, $m)) { $start = substr($m[1], 0, 1); diff --git a/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php b/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php index 34cced688..f5fd2d4dc 100644 --- a/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php +++ b/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php @@ -63,8 +63,9 @@ public function current(): SplFileInfo $subPathname .= $this->directorySeparator; } $subPathname .= $this->getFilename(); + $basePath = $this->rootPath; - if ('/' !== $basePath = $this->rootPath) { + if ('/' !== $basePath && !str_ends_with($basePath, $this->directorySeparator) && !str_ends_with($basePath, '/')) { $basePath .= $this->directorySeparator; } diff --git a/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php b/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php index 7e6051d38..b278706e9 100644 --- a/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php @@ -18,20 +18,17 @@ */ final class VcsIgnoredFilterIterator extends \FilterIterator { - /** - * @var string - */ - private $baseDir; + private string $baseDir; /** * @var array */ - private $gitignoreFilesCache = []; + private array $gitignoreFilesCache = []; /** * @var array */ - private $ignoredPathsCache = []; + private array $ignoredPathsCache = []; /** * @param \Iterator $iterator @@ -40,9 +37,9 @@ public function __construct(\Iterator $iterator, string $baseDir) { $this->baseDir = $this->normalizePath($baseDir); - foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) { - if (@is_dir("{$parentDirectory}/.git")) { - $this->baseDir = $parentDirectory; + foreach ([$this->baseDir, ...$this->parentDirectoriesUpwards($this->baseDir)] as $directory) { + if (@is_dir("{$directory}/.git")) { + $this->baseDir = $directory; break; } } diff --git a/app/vendor/symfony/finder/SplFileInfo.php b/app/vendor/symfony/finder/SplFileInfo.php index 867e8e81a..2afc37826 100644 --- a/app/vendor/symfony/finder/SplFileInfo.php +++ b/app/vendor/symfony/finder/SplFileInfo.php @@ -18,19 +18,17 @@ */ class SplFileInfo extends \SplFileInfo { - private string $relativePath; - private string $relativePathname; - /** * @param string $file The file name * @param string $relativePath The relative path * @param string $relativePathname The relative path name */ - public function __construct(string $file, string $relativePath, string $relativePathname) - { + public function __construct( + string $file, + private string $relativePath, + private string $relativePathname, + ) { parent::__construct($file); - $this->relativePath = $relativePath; - $this->relativePathname = $relativePathname; } /** diff --git a/app/vendor/symfony/finder/composer.json b/app/vendor/symfony/finder/composer.json index 06d129c56..2b70600d0 100644 --- a/app/vendor/symfony/finder/composer.json +++ b/app/vendor/symfony/finder/composer.json @@ -16,10 +16,10 @@ } ], "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.0" + "symfony/filesystem": "^6.4|^7.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" }, diff --git a/app/vendor/symfony/polyfill-ctype/composer.json b/app/vendor/symfony/polyfill-ctype/composer.json index e5c978f15..131ca7adb 100644 --- a/app/vendor/symfony/polyfill-ctype/composer.json +++ b/app/vendor/symfony/polyfill-ctype/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -30,9 +30,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-intl-grapheme/composer.json b/app/vendor/symfony/polyfill-intl-grapheme/composer.json index c00d4e9e4..0eea417d7 100644 --- a/app/vendor/symfony/polyfill-intl-grapheme/composer.json +++ b/app/vendor/symfony/polyfill-intl-grapheme/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Intl\\Grapheme\\": "" }, @@ -27,9 +27,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-intl-normalizer/composer.json b/app/vendor/symfony/polyfill-intl-normalizer/composer.json index 2c4de2c83..9bd04e887 100644 --- a/app/vendor/symfony/polyfill-intl-normalizer/composer.json +++ b/app/vendor/symfony/polyfill-intl-normalizer/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, @@ -28,9 +28,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-mbstring/Mbstring.php b/app/vendor/symfony/polyfill-mbstring/Mbstring.php index 2e0b96940..31e36a368 100644 --- a/app/vendor/symfony/polyfill-mbstring/Mbstring.php +++ b/app/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -48,6 +48,11 @@ * - mb_strstr - Finds first occurrence of a string within another * - mb_strwidth - Return width of string * - mb_substr_count - Count the number of substring occurrences + * - mb_ucfirst - Make a string's first character uppercase + * - mb_lcfirst - Make a string's first character lowercase + * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string + * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string + * - mb_rtrim - Strip whitespace (or other characters) from the end of a string * * Not implemented: * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) @@ -80,6 +85,15 @@ final class Mbstring public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) { + if (\is_array($s)) { + $r = []; + foreach ($s as $str) { + $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding); + } + + return $r; + } + if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) { $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); } else { @@ -410,12 +424,6 @@ public static function mb_encoding_aliases($encoding) public static function mb_check_encoding($var = null, $encoding = null) { - if (PHP_VERSION_ID < 70200 && \is_array($var)) { - trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING); - - return null; - } - if (null === $encoding) { if (null === $var) { return false; @@ -437,7 +445,6 @@ public static function mb_check_encoding($var = null, $encoding = null) } return true; - } public static function mb_detect_encoding($str, $encodingList = null, $strict = false) @@ -827,7 +834,7 @@ public static function mb_ord($s, $encoding = null) return $code; } - public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string + public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string { if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); @@ -835,17 +842,8 @@ public static function mb_str_pad(string $string, int $length, string $pad_strin if (null === $encoding) { $encoding = self::mb_internal_encoding(); - } - - try { - $validEncoding = @self::mb_check_encoding('', $encoding); - } catch (\ValueError $e) { - throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); - } - - // BC for PHP 7.3 and lower - if (!$validEncoding) { - throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } else { + self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given'); } if (self::mb_strlen($pad_string, $encoding) <= 0) { @@ -871,6 +869,34 @@ public static function mb_str_pad(string $string, int $length, string $pad_strin } } + public static function mb_ucfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + + public static function mb_lcfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + private static function getSubpart($pos, $part, $haystack, $encoding) { if (false === $pos) { @@ -944,4 +970,76 @@ private static function getEncoding($encoding) return $encoding; } + + public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given'); + } + + if ('' === $characters) { + return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding); + } + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $string)) { + $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); + } + if (null !== $characters && !preg_match('//u', $characters)) { + $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters); + } + } else { + $string = iconv($encoding, 'UTF-8//IGNORE', $string); + + if (null !== $characters) { + $characters = iconv($encoding, 'UTF-8//IGNORE', $characters); + } + } + + if (null === $characters) { + $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; + } else { + $characters = preg_quote($characters); + } + + $string = preg_replace(sprintf($regex, $characters), '', $string); + + if (null === $encoding) { + return $string; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $string); + } + + private static function assertEncoding(string $encoding, string $errorFormat): void + { + try { + $validEncoding = @self::mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + } } diff --git a/app/vendor/symfony/polyfill-mbstring/bootstrap.php b/app/vendor/symfony/polyfill-mbstring/bootstrap.php index ecf1a0352..ff51ae079 100644 --- a/app/vendor/symfony/polyfill-mbstring/bootstrap.php +++ b/app/vendor/symfony/polyfill-mbstring/bootstrap.php @@ -136,6 +136,27 @@ function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstrin function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + + if (extension_loaded('mbstring')) { return; } diff --git a/app/vendor/symfony/polyfill-mbstring/bootstrap80.php b/app/vendor/symfony/polyfill-mbstring/bootstrap80.php index 2f9fb5b42..5236e6dcc 100644 --- a/app/vendor/symfony/polyfill-mbstring/bootstrap80.php +++ b/app/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -93,7 +93,7 @@ function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?strin function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!function_exists('mb_get_info')) { - function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); } + function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); } } if (!function_exists('mb_http_output')) { function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } @@ -132,6 +132,26 @@ function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = nul function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + if (extension_loaded('mbstring')) { return; } diff --git a/app/vendor/symfony/polyfill-mbstring/composer.json b/app/vendor/symfony/polyfill-mbstring/composer.json index 943e50296..daa07f86b 100644 --- a/app/vendor/symfony/polyfill-mbstring/composer.json +++ b/app/vendor/symfony/polyfill-mbstring/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2", + "ext-iconv": "*" }, "provide": { "ext-mbstring": "*" @@ -30,9 +31,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-php73/composer.json b/app/vendor/symfony/polyfill-php73/composer.json index 48295ef97..09d98cb87 100644 --- a/app/vendor/symfony/polyfill-php73/composer.json +++ b/app/vendor/symfony/polyfill-php73/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Php73\\": "" }, @@ -25,9 +25,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-php80/PhpToken.php b/app/vendor/symfony/polyfill-php80/PhpToken.php index fe6e69105..cd78c4ccc 100644 --- a/app/vendor/symfony/polyfill-php80/PhpToken.php +++ b/app/vendor/symfony/polyfill-php80/PhpToken.php @@ -29,7 +29,7 @@ class PhpToken implements \Stringable public $text; /** - * @var int + * @var -1|positive-int */ public $line; @@ -38,6 +38,9 @@ class PhpToken implements \Stringable */ public $pos; + /** + * @param -1|positive-int $line + */ public function __construct(int $id, string $text, int $line = -1, int $position = -1) { $this->id = $id; @@ -80,7 +83,7 @@ public function __toString(): string } /** - * @return static[] + * @return list */ public static function tokenize(string $code, int $flags = 0): array { diff --git a/app/vendor/symfony/polyfill-php80/composer.json b/app/vendor/symfony/polyfill-php80/composer.json index f1801f403..a503b039a 100644 --- a/app/vendor/symfony/polyfill-php80/composer.json +++ b/app/vendor/symfony/polyfill-php80/composer.json @@ -20,7 +20,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, @@ -29,9 +29,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php b/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php index eb5952ee3..5ff93fcaf 100644 --- a/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php +++ b/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php @@ -32,7 +32,7 @@ public function __set(string $name, $value): void } if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) { - throw new \TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string'); + throw new TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string'); } $this->name = 'data://application/octet-stream;base64,'.base64_encode($value); diff --git a/app/vendor/symfony/polyfill-php81/composer.json b/app/vendor/symfony/polyfill-php81/composer.json index e02d673d4..28b6408ea 100644 --- a/app/vendor/symfony/polyfill-php81/composer.json +++ b/app/vendor/symfony/polyfill-php81/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Php81\\": "" }, @@ -25,9 +25,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/process/CHANGELOG.md b/app/vendor/symfony/process/CHANGELOG.md index 31b9ee6a2..3e33cd0bc 100644 --- a/app/vendor/symfony/process/CHANGELOG.md +++ b/app/vendor/symfony/process/CHANGELOG.md @@ -1,6 +1,18 @@ CHANGELOG ========= +7.1 +--- + + * Add `Process::setIgnoredSignals()` to disable signal propagation to the child process + +6.4 +--- + + * Add `PhpSubprocess` to handle PHP subprocesses that take over the + configuration from their parent + * Add `RunProcessMessage` and `RunProcessMessageHandler` + 5.2.0 ----- diff --git a/app/vendor/symfony/process/Exception/ProcessFailedException.php b/app/vendor/symfony/process/Exception/ProcessFailedException.php index cf006daeb..de8a9e983 100644 --- a/app/vendor/symfony/process/Exception/ProcessFailedException.php +++ b/app/vendor/symfony/process/Exception/ProcessFailedException.php @@ -20,15 +20,14 @@ */ class ProcessFailedException extends RuntimeException { - private $process; - - public function __construct(Process $process) - { + public function __construct( + private Process $process, + ) { if ($process->isSuccessful()) { throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); } - $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", + $error = \sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText(), @@ -36,7 +35,7 @@ public function __construct(Process $process) ); if (!$process->isOutputDisabled()) { - $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", + $error .= \sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput() ); @@ -47,10 +46,7 @@ public function __construct(Process $process) $this->process = $process; } - /** - * @return Process - */ - public function getProcess() + public function getProcess(): Process { return $this->process; } diff --git a/app/vendor/symfony/process/Exception/ProcessSignaledException.php b/app/vendor/symfony/process/Exception/ProcessSignaledException.php index d4d322756..3fd13e5d7 100644 --- a/app/vendor/symfony/process/Exception/ProcessSignaledException.php +++ b/app/vendor/symfony/process/Exception/ProcessSignaledException.php @@ -20,13 +20,10 @@ */ final class ProcessSignaledException extends RuntimeException { - private $process; - - public function __construct(Process $process) - { - $this->process = $process; - - parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); + public function __construct( + private Process $process, + ) { + parent::__construct(\sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); } public function getProcess(): Process diff --git a/app/vendor/symfony/process/Exception/ProcessStartFailedException.php b/app/vendor/symfony/process/Exception/ProcessStartFailedException.php new file mode 100644 index 000000000..372547259 --- /dev/null +++ b/app/vendor/symfony/process/Exception/ProcessStartFailedException.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Exception; + +use Symfony\Component\Process\Process; + +/** + * Exception for processes failed during startup. + */ +class ProcessStartFailedException extends ProcessFailedException +{ + public function __construct( + private Process $process, + ?string $message, + ) { + if ($process->isStarted()) { + throw new InvalidArgumentException('Expected a process that failed during startup, but the given process was started successfully.'); + } + + $error = \sprintf('The command "%s" failed.'."\n\nWorking directory: %s\n\nError: %s", + $process->getCommandLine(), + $process->getWorkingDirectory(), + $message ?? 'unknown' + ); + + // Skip parent constructor + RuntimeException::__construct($error); + } + + public function getProcess(): Process + { + return $this->process; + } +} diff --git a/app/vendor/symfony/process/Exception/ProcessTimedOutException.php b/app/vendor/symfony/process/Exception/ProcessTimedOutException.php index e507ca309..d3fe49342 100644 --- a/app/vendor/symfony/process/Exception/ProcessTimedOutException.php +++ b/app/vendor/symfony/process/Exception/ProcessTimedOutException.php @@ -23,41 +23,28 @@ class ProcessTimedOutException extends RuntimeException public const TYPE_GENERAL = 1; public const TYPE_IDLE = 2; - private $process; - private $timeoutType; - - public function __construct(Process $process, int $timeoutType) - { - $this->process = $process; - $this->timeoutType = $timeoutType; - - parent::__construct(sprintf( + public function __construct( + private Process $process, + private int $timeoutType, + ) { + parent::__construct(\sprintf( 'The process "%s" exceeded the timeout of %s seconds.', $process->getCommandLine(), $this->getExceededTimeout() )); } - /** - * @return Process - */ - public function getProcess() + public function getProcess(): Process { return $this->process; } - /** - * @return bool - */ - public function isGeneralTimeout() + public function isGeneralTimeout(): bool { return self::TYPE_GENERAL === $this->timeoutType; } - /** - * @return bool - */ - public function isIdleTimeout() + public function isIdleTimeout(): bool { return self::TYPE_IDLE === $this->timeoutType; } @@ -67,7 +54,7 @@ public function getExceededTimeout(): ?float return match ($this->timeoutType) { self::TYPE_GENERAL => $this->process->getTimeout(), self::TYPE_IDLE => $this->process->getIdleTimeout(), - default => throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType)), + default => throw new \LogicException(\sprintf('Unknown timeout type "%d".', $this->timeoutType)), }; } } diff --git a/app/vendor/symfony/process/Exception/RunProcessFailedException.php b/app/vendor/symfony/process/Exception/RunProcessFailedException.php new file mode 100644 index 000000000..e7219d351 --- /dev/null +++ b/app/vendor/symfony/process/Exception/RunProcessFailedException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Exception; + +use Symfony\Component\Process\Messenger\RunProcessContext; + +/** + * @author Kevin Bond + */ +final class RunProcessFailedException extends RuntimeException +{ + public function __construct(ProcessFailedException $exception, public readonly RunProcessContext $context) + { + parent::__construct($exception->getMessage(), $exception->getCode()); + } +} diff --git a/app/vendor/symfony/process/ExecutableFinder.php b/app/vendor/symfony/process/ExecutableFinder.php index e3387dfe1..5cc652512 100644 --- a/app/vendor/symfony/process/ExecutableFinder.php +++ b/app/vendor/symfony/process/ExecutableFinder.php @@ -19,24 +19,31 @@ */ class ExecutableFinder { - private $suffixes = ['.exe', '.bat', '.cmd', '.com']; + private const CMD_BUILTINS = [ + 'assoc', 'break', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date', + 'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto', + 'help', 'if', 'label', 'md', 'mkdir', 'mklink', 'move', 'path', 'pause', + 'popd', 'prompt', 'pushd', 'rd', 'rem', 'ren', 'rename', 'rmdir', 'set', + 'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'vol', + ]; + + private array $suffixes = []; /** * Replaces default suffixes of executable. - * - * @return void */ - public function setSuffixes(array $suffixes) + public function setSuffixes(array $suffixes): void { $this->suffixes = $suffixes; } /** - * Adds new possible suffix to check for executable. + * Adds new possible suffix to check for executable, including the dot (.). * - * @return void + * $finder = new ExecutableFinder(); + * $finder->addSuffix('.foo'); */ - public function addSuffix(string $suffix) + public function addSuffix(string $suffix): void { $this->suffixes[] = $suffix; } @@ -48,41 +55,49 @@ public function addSuffix(string $suffix) * @param string|null $default The default to return if no executable is found * @param array $extraDirs Additional dirs to check into */ - public function find(string $name, string $default = null, array $extraDirs = []): ?string + public function find(string $name, ?string $default = null, array $extraDirs = []): ?string { - if (\ini_get('open_basedir')) { - $searchPath = array_merge(explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs); - $dirs = []; - foreach ($searchPath as $path) { - // Silencing against https://bugs.php.net/69240 - if (@is_dir($path)) { - $dirs[] = $path; - } else { - if (basename($path) == $name && @is_executable($path)) { - return $path; - } - } - } - } else { - $dirs = array_merge( - explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')), - $extraDirs - ); + // windows built-in commands that are present in cmd.exe should not be resolved using PATH as they do not exist as exes + if ('\\' === \DIRECTORY_SEPARATOR && \in_array(strtolower($name), self::CMD_BUILTINS, true)) { + return $name; } - $suffixes = ['']; + $dirs = array_merge( + explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')), + $extraDirs + ); + + $suffixes = $this->suffixes; if ('\\' === \DIRECTORY_SEPARATOR) { $pathExt = getenv('PATHEXT'); - $suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes); + $suffixes = array_merge($suffixes, $pathExt ? explode(\PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com']); } + $suffixes = '' !== pathinfo($name, PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']); foreach ($suffixes as $suffix) { foreach ($dirs as $dir) { + if ('' === $dir) { + $dir = '.'; + } if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) { return $file; } + + if (!@is_dir($dir) && basename($dir) === $name.$suffix && @is_executable($dir)) { + return $dir; + } } } + if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('exec') || \strlen($name) !== strcspn($name, '/'.\DIRECTORY_SEPARATOR)) { + return $default; + } + + $execResult = exec('command -v -- '.escapeshellarg($name)); + + if (($executablePath = substr($execResult, 0, strpos($execResult, \PHP_EOL) ?: null)) && @is_executable($executablePath)) { + return $executablePath; + } + return $default; } } diff --git a/app/vendor/symfony/process/InputStream.php b/app/vendor/symfony/process/InputStream.php index 086f5a9ed..586e74293 100644 --- a/app/vendor/symfony/process/InputStream.php +++ b/app/vendor/symfony/process/InputStream.php @@ -22,19 +22,16 @@ */ class InputStream implements \IteratorAggregate { - /** @var callable|null */ - private $onEmpty; - private $input = []; - private $open = true; + private ?\Closure $onEmpty = null; + private array $input = []; + private bool $open = true; /** * Sets a callback that is called when the write buffer becomes empty. - * - * @return void */ - public function onEmpty(callable $onEmpty = null) + public function onEmpty(?callable $onEmpty = null): void { - $this->onEmpty = $onEmpty; + $this->onEmpty = null !== $onEmpty ? $onEmpty(...) : null; } /** @@ -42,36 +39,30 @@ public function onEmpty(callable $onEmpty = null) * * @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar, * stream resource or \Traversable - * - * @return void */ - public function write(mixed $input) + public function write(mixed $input): void { if (null === $input) { return; } if ($this->isClosed()) { - throw new RuntimeException(sprintf('"%s" is closed.', static::class)); + throw new RuntimeException(\sprintf('"%s" is closed.', static::class)); } $this->input[] = ProcessUtils::validateInput(__METHOD__, $input); } /** * Closes the write buffer. - * - * @return void */ - public function close() + public function close(): void { $this->open = false; } /** * Tells whether the write buffer is closed or not. - * - * @return bool */ - public function isClosed() + public function isClosed(): bool { return !$this->open; } diff --git a/app/vendor/symfony/process/Messenger/RunProcessContext.php b/app/vendor/symfony/process/Messenger/RunProcessContext.php new file mode 100644 index 000000000..5e2230404 --- /dev/null +++ b/app/vendor/symfony/process/Messenger/RunProcessContext.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Messenger; + +use Symfony\Component\Process\Process; + +/** + * @author Kevin Bond + */ +final class RunProcessContext +{ + public readonly ?int $exitCode; + public readonly ?string $output; + public readonly ?string $errorOutput; + + public function __construct( + public readonly RunProcessMessage $message, + Process $process, + ) { + $this->exitCode = $process->getExitCode(); + $this->output = !$process->isStarted() || $process->isOutputDisabled() ? null : $process->getOutput(); + $this->errorOutput = !$process->isStarted() || $process->isOutputDisabled() ? null : $process->getErrorOutput(); + } +} diff --git a/app/vendor/symfony/process/Messenger/RunProcessMessage.php b/app/vendor/symfony/process/Messenger/RunProcessMessage.php new file mode 100644 index 000000000..b2c33fe3b --- /dev/null +++ b/app/vendor/symfony/process/Messenger/RunProcessMessage.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Messenger; + +/** + * @author Kevin Bond + */ +class RunProcessMessage implements \Stringable +{ + public function __construct( + public readonly array $command, + public readonly ?string $cwd = null, + public readonly ?array $env = null, + public readonly mixed $input = null, + public readonly ?float $timeout = 60.0, + ) { + } + + public function __toString(): string + { + return implode(' ', $this->command); + } +} diff --git a/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php b/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php new file mode 100644 index 000000000..41c1934cc --- /dev/null +++ b/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Messenger; + +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Exception\RunProcessFailedException; +use Symfony\Component\Process\Process; + +/** + * @author Kevin Bond + */ +final class RunProcessMessageHandler +{ + public function __invoke(RunProcessMessage $message): RunProcessContext + { + $process = new Process($message->command, $message->cwd, $message->env, $message->input, $message->timeout); + + try { + return new RunProcessContext($message, $process->mustRun()); + } catch (ProcessFailedException $e) { + throw new RunProcessFailedException($e, new RunProcessContext($message, $e->getProcess())); + } + } +} diff --git a/app/vendor/symfony/process/PhpExecutableFinder.php b/app/vendor/symfony/process/PhpExecutableFinder.php index 9ab8ac23f..9f9218f98 100644 --- a/app/vendor/symfony/process/PhpExecutableFinder.php +++ b/app/vendor/symfony/process/PhpExecutableFinder.php @@ -19,7 +19,7 @@ */ class PhpExecutableFinder { - private $executableFinder; + private ExecutableFinder $executableFinder; public function __construct() { @@ -32,15 +32,8 @@ public function __construct() public function find(bool $includeArgs = true): string|false { if ($php = getenv('PHP_BINARY')) { - if (!is_executable($php)) { - $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v'; - if ($php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) { - if (!is_executable($php)) { - return false; - } - } else { - return false; - } + if (!is_executable($php) && !$php = $this->executableFinder->find($php)) { + return false; } if (@is_dir($php)) { @@ -81,6 +74,10 @@ public function find(bool $includeArgs = true): string|false $dirs[] = 'C:\xampp\php\\'; } + if ($herdPath = getenv('HERD_HOME')) { + $dirs[] = $herdPath.\DIRECTORY_SEPARATOR.'bin'; + } + return $this->executableFinder->find('php', false, $dirs); } diff --git a/app/vendor/symfony/process/PhpProcess.php b/app/vendor/symfony/process/PhpProcess.php index ef54a3d2b..0e7ff8464 100644 --- a/app/vendor/symfony/process/PhpProcess.php +++ b/app/vendor/symfony/process/PhpProcess.php @@ -32,7 +32,7 @@ class PhpProcess extends Process * @param int $timeout The timeout in seconds * @param array|null $php Path to the PHP binary to use with any additional arguments */ - public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60, array $php = null) + public function __construct(string $script, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) { if (null === $php) { $executableFinder = new PhpExecutableFinder(); @@ -50,15 +50,12 @@ public function __construct(string $script, string $cwd = null, array $env = nul parent::__construct($php, $cwd, $env, $script, $timeout); } - public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { - throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); } - /** - * @return void - */ - public function start(callable $callback = null, array $env = []) + public function start(?callable $callback = null, array $env = []): void { if (null === $this->getCommandLine()) { throw new RuntimeException('Unable to find the PHP executable.'); diff --git a/app/vendor/symfony/process/PhpSubprocess.php b/app/vendor/symfony/process/PhpSubprocess.php new file mode 100644 index 000000000..bdd4173c2 --- /dev/null +++ b/app/vendor/symfony/process/PhpSubprocess.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process; + +use Symfony\Component\Process\Exception\LogicException; +use Symfony\Component\Process\Exception\RuntimeException; + +/** + * PhpSubprocess runs a PHP command as a subprocess while keeping the original php.ini settings. + * + * For this, it generates a temporary php.ini file taking over all the current settings and disables + * loading additional .ini files. Basically, your command gets prefixed using "php -n -c /tmp/temp.ini". + * + * Given your php.ini contains "memory_limit=-1" and you have a "MemoryTest.php" with the following content: + * + * run(); + * print $p->getOutput()."\n"; + * + * This will output "string(2) "-1", because the process is started with the default php.ini settings. + * + * $p = new PhpSubprocess(['MemoryTest.php'], null, null, 60, ['php', '-d', 'memory_limit=256M']); + * $p->run(); + * print $p->getOutput()."\n"; + * + * This will output "string(4) "256M"", because the process is started with the temporarily created php.ini settings. + * + * @author Yanick Witschi + * @author Partially copied and heavily inspired from composer/xdebug-handler by John Stevenson + */ +class PhpSubprocess extends Process +{ + /** + * @param array $command The command to run and its arguments listed as separate entries. They will automatically + * get prefixed with the PHP binary + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param int $timeout The timeout in seconds + * @param array|null $php Path to the PHP binary to use with any additional arguments + */ + public function __construct(array $command, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) + { + if (null === $php) { + $executableFinder = new PhpExecutableFinder(); + $php = $executableFinder->find(false); + $php = false === $php ? null : array_merge([$php], $executableFinder->findArguments()); + } + + if (null === $php) { + throw new RuntimeException('Unable to find PHP binary.'); + } + + $tmpIni = $this->writeTmpIni($this->getAllIniFiles(), sys_get_temp_dir()); + + $php = array_merge($php, ['-n', '-c', $tmpIni]); + register_shutdown_function('unlink', $tmpIni); + + $command = array_merge($php, $command); + + parent::__construct($command, $cwd, $env, null, $timeout); + } + + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static + { + throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + } + + public function start(?callable $callback = null, array $env = []): void + { + if (null === $this->getCommandLine()) { + throw new RuntimeException('Unable to find the PHP executable.'); + } + + parent::start($callback, $env); + } + + private function writeTmpIni(array $iniFiles, string $tmpDir): string + { + if (false === $tmpfile = @tempnam($tmpDir, '')) { + throw new RuntimeException('Unable to create temporary ini file.'); + } + + // $iniFiles has at least one item and it may be empty + if ('' === $iniFiles[0]) { + array_shift($iniFiles); + } + + $content = ''; + + foreach ($iniFiles as $file) { + // Check for inaccessible ini files + if (($data = @file_get_contents($file)) === false) { + throw new RuntimeException('Unable to read ini: '.$file); + } + // Check and remove directives after HOST and PATH sections + if (preg_match('/^\s*\[(?:PATH|HOST)\s*=/mi', $data, $matches, \PREG_OFFSET_CAPTURE)) { + $data = substr($data, 0, $matches[0][1]); + } + + $content .= $data."\n"; + } + + // Merge loaded settings into our ini content, if it is valid + $config = parse_ini_string($content); + $loaded = ini_get_all(null, false); + + if (false === $config || false === $loaded) { + throw new RuntimeException('Unable to parse ini data.'); + } + + $content .= $this->mergeLoadedConfig($loaded, $config); + + // Work-around for https://bugs.php.net/bug.php?id=75932 + $content .= "opcache.enable_cli=0\n"; + + if (false === @file_put_contents($tmpfile, $content)) { + throw new RuntimeException('Unable to write temporary ini file.'); + } + + return $tmpfile; + } + + private function mergeLoadedConfig(array $loadedConfig, array $iniConfig): string + { + $content = ''; + + foreach ($loadedConfig as $name => $value) { + if (!\is_string($value)) { + continue; + } + + if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) { + // Double-quote escape each value + $content .= $name.'="'.addcslashes($value, '\\"')."\"\n"; + } + } + + return $content; + } + + private function getAllIniFiles(): array + { + $paths = [(string) php_ini_loaded_file()]; + + if (false !== $scanned = php_ini_scanned_files()) { + $paths = array_merge($paths, array_map('trim', explode(',', $scanned))); + } + + return $paths; + } +} diff --git a/app/vendor/symfony/process/Pipes/AbstractPipes.php b/app/vendor/symfony/process/Pipes/AbstractPipes.php index ba3a97a3f..51a566f3b 100644 --- a/app/vendor/symfony/process/Pipes/AbstractPipes.php +++ b/app/vendor/symfony/process/Pipes/AbstractPipes.php @@ -22,20 +22,19 @@ abstract class AbstractPipes implements PipesInterface { public array $pipes = []; - private $inputBuffer = ''; + private string $inputBuffer = ''; + /** @var resource|string|\Iterator */ private $input; - private $blocked = true; - private $lastError; + private bool $blocked = true; + private ?string $lastError = null; /** - * @param resource|string|int|float|bool|\Iterator|null $input + * @param resource|string|\Iterator $input */ - public function __construct(mixed $input) + public function __construct($input) { if (\is_resource($input) || $input instanceof \Iterator) { $this->input = $input; - } elseif (\is_string($input)) { - $this->inputBuffer = $input; } else { $this->inputBuffer = (string) $input; } @@ -102,7 +101,7 @@ protected function write(): ?array } elseif (!isset($this->inputBuffer[0])) { if (!\is_string($input)) { if (!\is_scalar($input)) { - throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input))); + throw new InvalidArgumentException(\sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input))); } $input = (string) $input; } diff --git a/app/vendor/symfony/process/Pipes/UnixPipes.php b/app/vendor/symfony/process/Pipes/UnixPipes.php index aba0efced..6f95a3328 100644 --- a/app/vendor/symfony/process/Pipes/UnixPipes.php +++ b/app/vendor/symfony/process/Pipes/UnixPipes.php @@ -22,16 +22,12 @@ */ class UnixPipes extends AbstractPipes { - private $ttyMode; - private $ptyMode; - private $haveReadSupport; - - public function __construct(?bool $ttyMode, bool $ptyMode, mixed $input, bool $haveReadSupport) - { - $this->ttyMode = $ttyMode; - $this->ptyMode = $ptyMode; - $this->haveReadSupport = $haveReadSupport; - + public function __construct( + private ?bool $ttyMode, + private bool $ptyMode, + mixed $input, + private bool $haveReadSupport, + ) { parent::__construct($input); } @@ -40,7 +36,7 @@ public function __sleep(): array throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup() + public function __wakeup(): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -74,7 +70,7 @@ public function getDescriptors(): array return [ ['pty'], ['pty'], - ['pty'], + ['pipe', 'w'], // stderr needs to be in a pipe to correctly split error and output, since PHP will use the same stream for both ]; } diff --git a/app/vendor/symfony/process/Pipes/WindowsPipes.php b/app/vendor/symfony/process/Pipes/WindowsPipes.php index 0d6ab12d3..116b8e30e 100644 --- a/app/vendor/symfony/process/Pipes/WindowsPipes.php +++ b/app/vendor/symfony/process/Pipes/WindowsPipes.php @@ -26,19 +26,18 @@ */ class WindowsPipes extends AbstractPipes { - private $files = []; - private $fileHandles = []; - private $lockHandles = []; - private $readBytes = [ + private array $files = []; + private array $fileHandles = []; + private array $lockHandles = []; + private array $readBytes = [ Process::STDOUT => 0, Process::STDERR => 0, ]; - private $haveReadSupport; - - public function __construct(mixed $input, bool $haveReadSupport) - { - $this->haveReadSupport = $haveReadSupport; + public function __construct( + mixed $input, + private bool $haveReadSupport, + ) { if ($this->haveReadSupport) { // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. // Workaround for this problem is to use temporary files instead of pipes on Windows platform. @@ -53,7 +52,7 @@ public function __construct(mixed $input, bool $haveReadSupport) set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); for ($i = 0;; ++$i) { foreach ($pipes as $pipe => $name) { - $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); + $file = \sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); if (!$h = fopen($file.'.lock', 'w')) { if (file_exists($file.'.lock')) { @@ -93,7 +92,7 @@ public function __sleep(): array throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup() + public function __wakeup(): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -140,7 +139,7 @@ public function readAndWrite(bool $blocking, bool $close = false): array if ($w) { @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6); } elseif ($this->fileHandles) { - usleep(Process::TIMEOUT_PRECISION * 1E6); + usleep((int) (Process::TIMEOUT_PRECISION * 1E6)); } } foreach ($this->fileHandles as $type => $fileHandle) { diff --git a/app/vendor/symfony/process/Process.php b/app/vendor/symfony/process/Process.php index 3e08b51fd..6fe1086ea 100644 --- a/app/vendor/symfony/process/Process.php +++ b/app/vendor/symfony/process/Process.php @@ -15,9 +15,9 @@ use Symfony\Component\Process\Exception\LogicException; use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\Exception\ProcessSignaledException; +use Symfony\Component\Process\Exception\ProcessStartFailedException; use Symfony\Component\Process\Exception\ProcessTimedOutException; use Symfony\Component\Process\Exception\RuntimeException; -use Symfony\Component\Process\Pipes\PipesInterface; use Symfony\Component\Process\Pipes\UnixPipes; use Symfony\Component\Process\Pipes\WindowsPipes; @@ -51,44 +51,47 @@ class Process implements \IteratorAggregate public const ITER_SKIP_OUT = 4; // Use this flag to skip STDOUT while iterating public const ITER_SKIP_ERR = 8; // Use this flag to skip STDERR while iterating - private $callback; - private $hasCallback = false; - private $commandline; - private $cwd; - private $env = []; + private ?\Closure $callback = null; + private array|string $commandline; + private ?string $cwd; + private array $env = []; + /** @var resource|string|\Iterator|null */ private $input; - private $starttime; - private $lastOutputTime; - private $timeout; - private $idleTimeout; - private $exitcode; - private $fallbackStatus = []; - private $processInformation; - private $outputDisabled = false; + private ?float $starttime = null; + private ?float $lastOutputTime = null; + private ?float $timeout = null; + private ?float $idleTimeout = null; + private ?int $exitcode = null; + private array $fallbackStatus = []; + private array $processInformation; + private bool $outputDisabled = false; + /** @var resource */ private $stdout; + /** @var resource */ private $stderr; + /** @var resource|null */ private $process; - private $status = self::STATUS_READY; - private $incrementalOutputOffset = 0; - private $incrementalErrorOutputOffset = 0; - private $tty = false; - private $pty; - private $options = ['suppress_errors' => true, 'bypass_shell' => true]; + private string $status = self::STATUS_READY; + private int $incrementalOutputOffset = 0; + private int $incrementalErrorOutputOffset = 0; + private bool $tty = false; + private bool $pty; + private array $options = ['suppress_errors' => true, 'bypass_shell' => true]; + private array $ignoredSignals = []; - private $useFileHandles = false; - /** @var PipesInterface */ - private $processPipes; + private WindowsPipes|UnixPipes $processPipes; - private $latestSignal; + private ?int $latestSignal = null; - private static $sigchild; + private static ?bool $sigchild = null; + private static array $executables = []; /** * Exit codes translation table. * * User-defined errors must use exit codes in the 64-113 range. */ - public static $exitCodes = [ + public static array $exitCodes = [ 0 => 'OK', 1 => 'General error', 2 => 'Misuse of shell builtins', @@ -140,7 +143,7 @@ class Process implements \IteratorAggregate * * @throws LogicException When proc_open is not installed */ - public function __construct(array $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60) + public function __construct(array $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60) { if (!\function_exists('proc_open')) { throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.'); @@ -162,7 +165,6 @@ public function __construct(array $command, string $cwd = null, array $env = nul $this->setInput($input); $this->setTimeout($timeout); - $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR; $this->pty = false; } @@ -187,7 +189,7 @@ public function __construct(array $command, string $cwd = null, array $env = nul * * @throws LogicException When proc_open is not installed */ - public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { $process = new static([], $cwd, $env, $input, $timeout); $process->commandline = $command; @@ -200,7 +202,7 @@ public function __sleep(): array throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup() + public function __wakeup(): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -234,15 +236,15 @@ public function __clone() * * @return int The exit status code * - * @throws RuntimeException When process can't be launched - * @throws RuntimeException When process is already running - * @throws ProcessTimedOutException When process timed out - * @throws ProcessSignaledException When process stopped after receiving signal - * @throws LogicException In case a callback is provided and output has been disabled + * @throws ProcessStartFailedException When process can't be launched + * @throws RuntimeException When process is already running + * @throws ProcessTimedOutException When process timed out + * @throws ProcessSignaledException When process stopped after receiving signal + * @throws LogicException In case a callback is provided and output has been disabled * * @final */ - public function run(callable $callback = null, array $env = []): int + public function run(?callable $callback = null, array $env = []): int { $this->start($callback, $env); @@ -261,7 +263,7 @@ public function run(callable $callback = null, array $env = []): int * * @final */ - public function mustRun(callable $callback = null, array $env = []): static + public function mustRun(?callable $callback = null, array $env = []): static { if (0 !== $this->run($callback, $env)) { throw new ProcessFailedException($this); @@ -285,13 +287,11 @@ public function mustRun(callable $callback = null, array $env = []): static * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR * - * @return void - * - * @throws RuntimeException When process can't be launched - * @throws RuntimeException When process is already running - * @throws LogicException In case a callback is provided and output has been disabled + * @throws ProcessStartFailedException When process can't be launched + * @throws RuntimeException When process is already running + * @throws LogicException In case a callback is provided and output has been disabled */ - public function start(callable $callback = null, array $env = []) + public function start(?callable $callback = null, array $env = []): void { if ($this->isRunning()) { throw new RuntimeException('Process is already running.'); @@ -300,8 +300,7 @@ public function start(callable $callback = null, array $env = []) $this->resetProcessData(); $this->starttime = $this->lastOutputTime = microtime(true); $this->callback = $this->buildCallback($callback); - $this->hasCallback = null !== $callback; - $descriptors = $this->getDescriptors(); + $descriptors = $this->getDescriptors(null !== $callback); if ($this->env) { $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env; @@ -310,29 +309,25 @@ public function start(callable $callback = null, array $env = []) $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->getDefaultEnv(), $env, 'strcasecmp') : $this->getDefaultEnv(); if (\is_array($commandline = $this->commandline)) { - $commandline = implode(' ', array_map($this->escapeArgument(...), $commandline)); - - if ('\\' !== \DIRECTORY_SEPARATOR) { - // exec is mandatory to deal with sending a signal to the process - $commandline = 'exec '.$commandline; - } + $commandline = array_values(array_map(strval(...), $commandline)); } else { $commandline = $this->replacePlaceholders($commandline, $env); } if ('\\' === \DIRECTORY_SEPARATOR) { $commandline = $this->prepareWindowsCommandLine($commandline, $env); - } elseif (!$this->useFileHandles && $this->isSigchildEnabled()) { + } elseif ($this->isSigchildEnabled()) { // last exit code is output on the fourth pipe and caught to work around --enable-sigchild $descriptors[3] = ['pipe', 'w']; + if (\is_array($commandline)) { + // exec is mandatory to deal with sending a signal to the process + $commandline = 'exec '.$this->buildShellCommandline($commandline); + } + // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;'; $commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code'; - - // Workaround for the bug, when PTS functionality is enabled. - // @see : https://bugs.php.net/69442 - $ptsWorkaround = fopen(__FILE__, 'r'); } $envPairs = []; @@ -343,14 +338,44 @@ public function start(callable $callback = null, array $env = []) } if (!is_dir($this->cwd)) { - throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd)); + throw new RuntimeException(\sprintf('The provided cwd "%s" does not exist.', $this->cwd)); } - $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); + $lastError = null; + set_error_handler(function ($type, $msg) use (&$lastError) { + $lastError = $msg; + + return true; + }); + + $oldMask = []; - if (!\is_resource($this->process)) { - throw new RuntimeException('Unable to launch a new process.'); + if ($this->ignoredSignals && \function_exists('pcntl_sigprocmask')) { + // we block signals we want to ignore, as proc_open will use fork / posix_spawn which will copy the signal mask this allow to block + // signals in the child process + pcntl_sigprocmask(\SIG_BLOCK, $this->ignoredSignals, $oldMask); } + + try { + $process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); + + // Ensure array vs string commands behave the same + if (!$process && \is_array($commandline)) { + $process = @proc_open('exec '.$this->buildShellCommandline($commandline), $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); + } + } finally { + if ($this->ignoredSignals && \function_exists('pcntl_sigprocmask')) { + // we restore the signal mask here to avoid any side effects + pcntl_sigprocmask(\SIG_SETMASK, $oldMask); + } + + restore_error_handler(); + } + + if (!$process) { + throw new ProcessStartFailedException($this, $lastError); + } + $this->process = $process; $this->status = self::STATUS_STARTED; if (isset($descriptors[3])) { @@ -373,14 +398,14 @@ public function start(callable $callback = null, array $env = []) * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR * - * @throws RuntimeException When process can't be launched - * @throws RuntimeException When process is already running + * @throws ProcessStartFailedException When process can't be launched + * @throws RuntimeException When process is already running * * @see start() * * @final */ - public function restart(callable $callback = null, array $env = []): static + public function restart(?callable $callback = null, array $env = []): static { if ($this->isRunning()) { throw new RuntimeException('Process is already running.'); @@ -407,7 +432,7 @@ public function restart(callable $callback = null, array $env = []): static * @throws ProcessSignaledException When process stopped after receiving signal * @throws LogicException When process is not yet started */ - public function wait(callable $callback = null): int + public function wait(?callable $callback = null): int { $this->requireProcessIsStarted(__FUNCTION__); @@ -880,7 +905,7 @@ public function getStatus(): string * * @return int|null The exit-code of the process or null if it's not running */ - public function stop(float $timeout = 10, int $signal = null): ?int + public function stop(float $timeout = 10, ?int $signal = null): ?int { $timeoutMicro = microtime(true) + $timeout; if ($this->isRunning()) { @@ -950,7 +975,7 @@ public function getLastOutputTime(): ?float */ public function getCommandLine(): string { - return \is_array($this->commandline) ? implode(' ', array_map($this->escapeArgument(...), $this->commandline)) : $this->commandline; + return $this->buildShellCommandline($this->commandline); } /** @@ -1119,7 +1144,7 @@ public function getInput() * * This content will be passed to the underlying process standard input. * - * @param string|int|float|bool|resource|\Traversable|null $input The content + * @param string|resource|\Traversable|self|null $input The content * * @return $this * @@ -1142,11 +1167,9 @@ public function setInput(mixed $input): static * In case you run a background process (with the start method), you should * trigger this method regularly to ensure the process timeout * - * @return void - * * @throws ProcessTimedOutException In case the timeout was reached */ - public function checkTimeout() + public function checkTimeout(): void { if (self::STATUS_STARTED !== $this->status) { return; @@ -1184,10 +1207,8 @@ public function getStartTime(): float * * Enabling the "create_new_console" option allows a subprocess to continue * to run after the main process exited, on both Windows and *nix - * - * @return void */ - public function setOptions(array $options) + public function setOptions(array $options): void { if ($this->isRunning()) { throw new RuntimeException('Setting options while the process is running is not possible.'); @@ -1199,12 +1220,26 @@ public function setOptions(array $options) foreach ($options as $key => $value) { if (!\in_array($key, $existingOptions)) { $this->options = $defaultOptions; - throw new LogicException(sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions))); + throw new LogicException(\sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions))); } $this->options[$key] = $value; } } + /** + * Defines a list of posix signals that will not be propagated to the process. + * + * @param list<\SIG*> $signals + */ + public function setIgnoredSignals(array $signals): void + { + if ($this->isRunning()) { + throw new RuntimeException('Setting ignored signals while the process is running is not possible.'); + } + + $this->ignoredSignals = $signals; + } + /** * Returns whether TTY is supported on the current operating system. */ @@ -1212,7 +1247,7 @@ public static function isTtySupported(): bool { static $isTtySupported; - return $isTtySupported ??= ('/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT)); + return $isTtySupported ??= ('/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT) && @is_writable('/dev/tty')); } /** @@ -1236,15 +1271,15 @@ public static function isPtySupported(): bool /** * Creates the descriptors needed by the proc_open. */ - private function getDescriptors(): array + private function getDescriptors(bool $hasCallback): array { if ($this->input instanceof \Iterator) { $this->input->rewind(); } if ('\\' === \DIRECTORY_SEPARATOR) { - $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback); + $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $hasCallback); } else { - $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback); + $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $hasCallback); } return $this->processPipes->getDescriptors(); @@ -1258,7 +1293,7 @@ private function getDescriptors(): array * * @param callable|null $callback The user defined PHP callback */ - protected function buildCallback(callable $callback = null): \Closure + protected function buildCallback(?callable $callback = null): \Closure { if ($this->outputDisabled) { return fn ($type, $data): bool => null !== $callback && $callback($type, $data); @@ -1281,16 +1316,16 @@ protected function buildCallback(callable $callback = null): \Closure * Updates the status of the process, reads pipes. * * @param bool $blocking Whether to use a blocking read call - * - * @return void */ - protected function updateStatus(bool $blocking) + protected function updateStatus(bool $blocking): void { if (self::STATUS_STARTED !== $this->status) { return; } - $this->processInformation = proc_get_status($this->process); + if ($this->processInformation['running'] ?? true) { + $this->processInformation = proc_get_status($this->process); + } $running = $this->processInformation['running']; $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running); @@ -1388,8 +1423,9 @@ private function readPipes(bool $blocking, bool $close): void private function close(): int { $this->processPipes->close(); - if (\is_resource($this->process)) { + if ($this->process) { proc_close($this->process); + $this->process = null; } $this->exitcode = $this->processInformation['exitcode']; $this->status = self::STATUS_TERMINATED; @@ -1421,7 +1457,7 @@ private function resetProcessData(): void $this->callback = null; $this->exitcode = null; $this->fallbackStatus = []; - $this->processInformation = null; + $this->processInformation = []; $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+'); $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+'); $this->process = null; @@ -1443,6 +1479,11 @@ private function resetProcessData(): void */ private function doSignal(int $signal, bool $throwException): bool { + // Signal seems to be send when sigchild is enable, this allow blocking the signal correctly in this case + if ($this->isSigchildEnabled() && \in_array($signal, $this->ignoredSignals)) { + return false; + } + if (null === $pid = $this->getPid()) { if ($throwException) { throw new LogicException('Cannot send signal on a non running process.'); @@ -1452,10 +1493,10 @@ private function doSignal(int $signal, bool $throwException): bool } if ('\\' === \DIRECTORY_SEPARATOR) { - exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode); + exec(\sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode); if ($exitCode && $this->isRunning()) { if ($throwException) { - throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output))); + throw new RuntimeException(\sprintf('Unable to kill the process (%s).', implode(' ', $output))); } return false; @@ -1465,12 +1506,12 @@ private function doSignal(int $signal, bool $throwException): bool $ok = @proc_terminate($this->process, $signal); } elseif (\function_exists('posix_kill')) { $ok = @posix_kill($pid, $signal); - } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) { + } elseif ($ok = proc_open(\sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) { $ok = false === fgets($pipes[2]); } if (!$ok) { if ($throwException) { - throw new RuntimeException(sprintf('Error while sending signal "%s".', $signal)); + throw new RuntimeException(\sprintf('Error while sending signal "%s".', $signal)); } return false; @@ -1485,9 +1526,25 @@ private function doSignal(int $signal, bool $throwException): bool return true; } - private function prepareWindowsCommandLine(string $cmd, array &$env): string + private function buildShellCommandline(string|array $commandline): string { - $uid = uniqid('', true); + if (\is_string($commandline)) { + return $commandline; + } + + if ('\\' === \DIRECTORY_SEPARATOR && isset($commandline[0][0]) && \strlen($commandline[0]) === strcspn($commandline[0], ':/\\')) { + // On Windows, we don't rely on the OS to find the executable if possible to avoid lookups + // in the current directory which could be untrusted. Instead we use the ExecutableFinder. + $commandline[0] = (self::$executables[$commandline[0]] ??= (new ExecutableFinder())->find($commandline[0])) ?? $commandline[0]; + } + + return implode(' ', array_map($this->escapeArgument(...), $commandline)); + } + + private function prepareWindowsCommandLine(string|array $cmd, array &$env): string + { + $cmd = $this->buildShellCommandline($cmd); + $uid = bin2hex(random_bytes(4)); $cmd = preg_replace_callback( '/"(?:( [^"%!^]*+ @@ -1523,7 +1580,14 @@ function ($m) use (&$env, $uid) { $cmd ); - $cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')'; + static $comSpec; + + if (!$comSpec && $comSpec = (new ExecutableFinder())->find('cmd.exe')) { + // Escape according to CommandLineToArgvW rules + $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec) .'"'; + } + + $cmd = ($comSpec ?? 'cmd').' /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')'; foreach ($this->processPipes->getFiles() as $offset => $filename) { $cmd .= ' '.$offset.'>"'.$filename.'"'; } @@ -1539,7 +1603,7 @@ function ($m) use (&$env, $uid) { private function requireProcessIsStarted(string $functionName): void { if (!$this->isStarted()) { - throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName)); + throw new LogicException(\sprintf('Process must be started before calling "%s()".', $functionName)); } } @@ -1551,7 +1615,7 @@ private function requireProcessIsStarted(string $functionName): void private function requireProcessIsTerminated(string $functionName): void { if (!$this->isTerminated()) { - throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName)); + throw new LogicException(\sprintf('Process must be terminated before calling "%s()".', $functionName)); } } @@ -1569,7 +1633,7 @@ private function escapeArgument(?string $argument): string if (str_contains($argument, "\0")) { $argument = str_replace("\0", '?', $argument); } - if (!preg_match('/[\/()%!^"<>&|\s]/', $argument)) { + if (!preg_match('/[()%!^"<>&|\s]/', $argument)) { return $argument; } $argument = preg_replace('/(\\\\+)$/', '$1$1', $argument); @@ -1581,7 +1645,7 @@ private function replacePlaceholders(string $commandline, array $env): string { return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) { if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) { - throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline); + throw new InvalidArgumentException(\sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline); } return $this->escapeArgument($env[$matches[1]]); diff --git a/app/vendor/symfony/process/ProcessUtils.php b/app/vendor/symfony/process/ProcessUtils.php index 744399d98..a2dbde9f7 100644 --- a/app/vendor/symfony/process/ProcessUtils.php +++ b/app/vendor/symfony/process/ProcessUtils.php @@ -43,9 +43,6 @@ public static function validateInput(string $caller, mixed $input): mixed if (\is_resource($input)) { return $input; } - if (\is_string($input)) { - return $input; - } if (\is_scalar($input)) { return (string) $input; } @@ -59,7 +56,7 @@ public static function validateInput(string $caller, mixed $input): mixed return new \IteratorIterator($input); } - throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); + throw new InvalidArgumentException(\sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); } return $input; diff --git a/app/vendor/symfony/process/composer.json b/app/vendor/symfony/process/composer.json index 317c07e71..dda5575ed 100644 --- a/app/vendor/symfony/process/composer.json +++ b/app/vendor/symfony/process/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.1" + "php": ">=8.2" }, "autoload": { "psr-4": { "Symfony\\Component\\Process\\": "" }, diff --git a/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php b/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php index d98e1dfdb..f850b8401 100644 --- a/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php +++ b/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php @@ -11,15 +11,15 @@ namespace Symfony\Contracts\Service\Attribute; +use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait; use Symfony\Contracts\Service\ServiceSubscriberInterface; -use Symfony\Contracts\Service\ServiceSubscriberTrait; /** * For use as the return value for {@see ServiceSubscriberInterface}. * * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi')) * - * Use with {@see ServiceSubscriberTrait} to mark a method's return type + * Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type * as a subscribed service. * * @author Kevin Bond diff --git a/app/vendor/symfony/service-contracts/ServiceCollectionInterface.php b/app/vendor/symfony/service-contracts/ServiceCollectionInterface.php new file mode 100644 index 000000000..2333139ce --- /dev/null +++ b/app/vendor/symfony/service-contracts/ServiceCollectionInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * A ServiceProviderInterface that is also countable and iterable. + * + * @author Kevin Bond + * + * @template-covariant T of mixed + * + * @extends ServiceProviderInterface + * @extends \IteratorAggregate + */ +interface ServiceCollectionInterface extends ServiceProviderInterface, \Countable, \IteratorAggregate +{ +} diff --git a/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php index 45c8d910d..b62ec3e53 100644 --- a/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php +++ b/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php @@ -31,7 +31,7 @@ trait ServiceLocatorTrait private array $providedTypes; /** - * @param callable[] $factories + * @param array $factories */ public function __construct(array $factories) { diff --git a/app/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php b/app/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php new file mode 100644 index 000000000..0d89d9f25 --- /dev/null +++ b/app/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @author Kevin Bond + */ +trait ServiceMethodsSubscriberTrait +{ + protected ContainerInterface $container; + + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key ??= self::class.'::'.$method->name; + $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + $attribute->nullable = $returnType->allowsNull(); + + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type; + } + } + + return $services; + } + + #[Required] + public function setContainer(ContainerInterface $container): ?ContainerInterface + { + $ret = null; + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + $ret = parent::setContainer($container); + } + + $this->container = $container; + + return $ret; + } +} diff --git a/app/vendor/symfony/service-contracts/ServiceProviderInterface.php b/app/vendor/symfony/service-contracts/ServiceProviderInterface.php index c05e4bfe7..2e71f00c6 100644 --- a/app/vendor/symfony/service-contracts/ServiceProviderInterface.php +++ b/app/vendor/symfony/service-contracts/ServiceProviderInterface.php @@ -39,7 +39,7 @@ public function has(string $id): bool; * * ['foo' => '?'] means the container provides service name "foo" of unspecified type * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null * - * @return string[] The provided service types, keyed by service names + * @return array The provided service types, keyed by service names */ public function getProvidedServices(): array; } diff --git a/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php index f3b450cd6..cc3bc321a 100644 --- a/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php +++ b/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php @@ -15,17 +15,23 @@ use Symfony\Contracts\Service\Attribute\Required; use Symfony\Contracts\Service\Attribute\SubscribedService; +trigger_deprecation('symfony/contracts', 'v3.5', '"%s" is deprecated, use "ServiceMethodsSubscriberTrait" instead.', ServiceSubscriberTrait::class); + /** - * Implementation of ServiceSubscriberInterface that determines subscribed services from - * method return types. Service ids are available as "ClassName::methodName". + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @property ContainerInterface $container * * @author Kevin Bond + * + * @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead */ trait ServiceSubscriberTrait { - /** @var ContainerInterface */ - protected $container; - public static function getSubscribedServices(): array { $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; diff --git a/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php index a0f20a6a7..65a3fe337 100644 --- a/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php +++ b/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -12,7 +12,9 @@ namespace Symfony\Contracts\Service\Test; use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Symfony\Contracts\Service\ServiceLocatorTrait; abstract class ServiceLocatorTestCase extends TestCase @@ -27,9 +29,9 @@ protected function getServiceLocator(array $factories): ContainerInterface public function testHas() { $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - function () { return 'dummy'; }, + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', + fn () => 'dummy', ]); $this->assertTrue($locator->has('foo')); @@ -40,8 +42,8 @@ function () { return 'dummy'; }, public function testGet() { $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', ]); $this->assertSame('bar', $locator->get('foo')); @@ -66,27 +68,29 @@ public function testGetDoesNotMemoize() 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'); }, ]); + if (!$this->getExpectedException()) { + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $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'); }, ]); + $this->expectException(ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator->get('foo'); } } diff --git a/app/vendor/symfony/service-contracts/composer.json b/app/vendor/symfony/service-contracts/composer.json index a64188b51..fc8674a72 100644 --- a/app/vendor/symfony/service-contracts/composer.json +++ b/app/vendor/symfony/service-contracts/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -31,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/app/vendor/symfony/string/AbstractString.php b/app/vendor/symfony/string/AbstractString.php index bf491f88d..500d7c311 100644 --- a/app/vendor/symfony/string/AbstractString.php +++ b/app/vendor/symfony/string/AbstractString.php @@ -39,8 +39,8 @@ abstract class AbstractString implements \Stringable, \JsonSerializable public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; - protected $string = ''; - protected $ignoreCase = false; + protected string $string = ''; + protected ?bool $ignoreCase = false; abstract public function __construct(string $string = ''); @@ -263,7 +263,7 @@ public function containsAny(string|iterable $needle): bool public function endsWith(string|iterable $suffix): bool { if (\is_string($suffix)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($suffix as $s) { @@ -312,7 +312,7 @@ public function ensureStart(string $prefix): static public function equalsTo(string|iterable $string): bool { if (\is_string($string)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($string as $s) { @@ -340,7 +340,7 @@ public function ignoreCase(): static public function indexOf(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = \PHP_INT_MAX; @@ -362,7 +362,7 @@ public function indexOf(string|iterable $needle, int $offset = 0): ?int public function indexOfLast(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = null; @@ -383,7 +383,7 @@ public function isEmpty(): bool return '' === $this->string; } - abstract public function join(array $strings, string $lastGlue = null): static; + abstract public function join(array $strings, ?string $lastGlue = null): static; public function jsonSerialize(): string { @@ -414,7 +414,7 @@ abstract public function prepend(string ...$prefix): static; public function repeat(int $multiplier): static { if (0 > $multiplier) { - throw new InvalidArgumentException(sprintf('Multiplier must be positive, %d given.', $multiplier)); + throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier)); } $str = clone $this; @@ -429,16 +429,21 @@ abstract public function replaceMatches(string $fromRegexp, string|callable $to) abstract public function reverse(): static; - abstract public function slice(int $start = 0, int $length = null): static; + abstract public function slice(int $start = 0, ?int $length = null): static; abstract public function snake(): static; - abstract public function splice(string $replacement, int $start = 0, int $length = null): static; + public function kebab(): static + { + return $this->snake()->replace('_', '-'); + } + + abstract public function splice(string $replacement, int $start = 0, ?int $length = null): static; /** * @return static[] */ - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (null === $flags) { throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.'); @@ -448,7 +453,7 @@ public function split(string $delimiter, int $limit = null, int $flags = null): $delimiter .= 'i'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) { @@ -481,7 +486,7 @@ public function split(string $delimiter, int $limit = null, int $flags = null): public function startsWith(string|iterable $prefix): bool { if (\is_string($prefix)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($prefix as $prefix) { @@ -495,7 +500,7 @@ public function startsWith(string|iterable $prefix): bool abstract public function title(bool $allWords = false): static; - public function toByteString(string $toEncoding = null): ByteString + public function toByteString(?string $toEncoding = null): ByteString { $b = new ByteString(); @@ -507,20 +512,14 @@ public function toByteString(string $toEncoding = null): ByteString return $b; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); - try { - try { - $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); - } catch (InvalidArgumentException $e) { - if (!\function_exists('iconv')) { - throw $e; - } - - $b->string = iconv('UTF-8', $toEncoding, $this->string); + $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); + } catch (\ValueError $e) { + if (!\function_exists('iconv')) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } - } finally { - restore_error_handler(); + + $b->string = iconv('UTF-8', $toEncoding, $this->string); } return $b; @@ -611,7 +610,7 @@ public function trimSuffix($suffix): static return $str; } - public function truncate(int $length, string $ellipsis = '', bool $cut = true): static + public function truncate(int $length, string $ellipsis = '', bool|TruncateMode $cut = TruncateMode::Char): static { $stringLength = $this->length(); @@ -625,16 +624,27 @@ public function truncate(int $length, string $ellipsis = '', bool $cut = true): $ellipsisLength = 0; } - if (!$cut) { + $desiredLength = $length; + if (TruncateMode::WordAfter === $cut || !$cut) { if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) { return clone $this; } + $length += $ellipsisLength; + } elseif (TruncateMode::WordBefore === $cut && null !== $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) { $length += $ellipsisLength; } $str = $this->slice(0, $length - $ellipsisLength); + if (TruncateMode::WordBefore === $cut) { + if (0 === $ellipsisLength && $desiredLength === $this->indexOf([' ', "\r", "\n", "\t"], $length)) { + return $str; + } + + $str = $str->beforeLast([' ', "\r", "\n", "\t"]); + } + return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; } diff --git a/app/vendor/symfony/string/AbstractUnicodeString.php b/app/vendor/symfony/string/AbstractUnicodeString.php index d19a61a9c..cf280cdba 100644 --- a/app/vendor/symfony/string/AbstractUnicodeString.php +++ b/app/vendor/symfony/string/AbstractUnicodeString.php @@ -44,9 +44,9 @@ abstract class AbstractUnicodeString extends AbstractString 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', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; - private static $transliterators = []; - private static $tableZero; - private static $tableWide; + private static array $transliterators = []; + private static array $tableZero; + private static array $tableWide; public static function fromCodePoints(int ...$codes): static { @@ -124,7 +124,7 @@ public function ascii(array $rules = []): self } if (null === $transliterator) { - throw new InvalidArgumentException(sprintf('Unknown transliteration rule "%s".', $rule)); + throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule)); } self::$transliterators['any-latin/bgn'] = $transliterator; @@ -135,15 +135,21 @@ public function ascii(array $rules = []): self } elseif (!\function_exists('iconv')) { $s = preg_replace('/[^\x00-\x7F]/u', '?', $s); } else { - $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { - $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); - - if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { - throw new \LogicException(sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); - } + $previousLocale = setlocale(\LC_CTYPE, 0); + try { + setlocale(\LC_CTYPE, 'C'); + $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { + $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); + + if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { + throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); + } - return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); - }, $s); + return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); + }, $s); + } finally { + setlocale(\LC_CTYPE, $previousLocale); + } } } @@ -155,7 +161,7 @@ public function ascii(array $rules = []): self public function camel(): static { $str = clone $this; - $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) { + $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?!\p{Lu})/u', static function ($m) { static $i = 0; return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); @@ -190,7 +196,7 @@ public function folded(bool $compat = true): static if (!$compat || !\defined('Normalizer::NFKC_CF')) { $str->string = normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC); - $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $this->string), 'UTF-8'); + $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $str->string), 'UTF-8'); } else { $str->string = normalizer_normalize($str->string, \Normalizer::NFKC_CF); } @@ -198,7 +204,7 @@ public function folded(bool $compat = true): static return $str; } - public function join(array $strings, string $lastGlue = null): static + public function join(array $strings, ?string $lastGlue = null): static { $str = clone $this; @@ -220,6 +226,21 @@ public function lower(): static return $str; } + /** + * @param string $locale In the format language_region (e.g. tr_TR) + */ + public function localeLower(string $locale): static + { + if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Lower')) { + $str = clone $this; + $str->string = $transliterator->transliterate($str->string); + + return $str; + } + + return $this->lower(); + } + public function match(string $regexp, int $flags = 0, int $offset = 0): array { $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match'; @@ -228,7 +249,7 @@ public function match(string $regexp, int $flags = 0, int $offset = 0): array $regexp .= 'i'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (false === $match($regexp.'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { @@ -312,7 +333,7 @@ public function replaceMatches(string $fromRegexp, string|callable $to): static $replace = 'preg_replace'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (null === $string = $replace($fromRegexp.'u', $to, $this->string)) { @@ -363,6 +384,21 @@ public function title(bool $allWords = false): static return $str; } + /** + * @param string $locale In the format language_region (e.g. tr_TR) + */ + public function localeTitle(string $locale): static + { + if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Title')) { + $str = clone $this; + $str->string = $transliterator->transliterate($str->string); + + return $str; + } + + return $this->title(); + } + public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static { if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { @@ -450,6 +486,21 @@ public function upper(): static return $str; } + /** + * @param string $locale In the format language_region (e.g. tr_TR) + */ + public function localeUpper(string $locale): static + { + if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Upper')) { + $str = clone $this; + $str->string = $transliterator->transliterate($str->string); + + return $str; + } + + return $this->upper(); + } + public function width(bool $ignoreAnsiDecoration = true): int { $width = 0; @@ -587,4 +638,33 @@ private function wcswidth(string $string): int return $width; } + + private function getLocaleTransliterator(string $locale, string $id): ?\Transliterator + { + $rule = $locale.'-'.$id; + if (\array_key_exists($rule, self::$transliterators)) { + return self::$transliterators[$rule]; + } + + if (null !== $transliterator = self::$transliterators[$rule] = \Transliterator::create($rule)) { + return $transliterator; + } + + // Try to find a parent locale (nl_BE -> nl) + if (false === $i = strpos($locale, '_')) { + return null; + } + + $parentRule = substr_replace($locale, '-'.$id, $i); + + // Parent locale was already cached, return and store as current locale + if (\array_key_exists($parentRule, self::$transliterators)) { + return self::$transliterators[$rule] = self::$transliterators[$parentRule]; + } + + // Create transliterator based on parent locale and cache the result on both initial and parent locale values + $transliterator = \Transliterator::create($parentRule); + + return self::$transliterators[$rule] = self::$transliterators[$parentRule] = $transliterator; + } } diff --git a/app/vendor/symfony/string/ByteString.php b/app/vendor/symfony/string/ByteString.php index 212290fed..5cbfd6de4 100644 --- a/app/vendor/symfony/string/ByteString.php +++ b/app/vendor/symfony/string/ByteString.php @@ -11,6 +11,7 @@ namespace Symfony\Component\String; +use Random\Randomizer; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; @@ -42,10 +43,10 @@ public function __construct(string $string = '') * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) */ - public static function fromRandom(int $length = 16, string $alphabet = null): self + public static function fromRandom(int $length = 16, ?string $alphabet = null): self { if ($length <= 0) { - throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length)); + throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length)); } $alphabet ??= self::ALPHABET_ALPHANUMERIC; @@ -55,6 +56,10 @@ public static function fromRandom(int $length = 16, string $alphabet = null): se throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); } + if (\PHP_VERSION_ID >= 80300) { + return new static((new Randomizer())->getBytesFromString($alphabet, $length)); + } + $ret = ''; while ($length > 0) { $urandomLength = (int) ceil(2 * $length * $bits / 8.0); @@ -205,7 +210,7 @@ public function isUtf8(): bool return '' === $this->string || preg_match('//u', $this->string); } - public function join(array $strings, string $lastGlue = null): static + public function join(array $strings, ?string $lastGlue = null): static { $str = clone $this; @@ -236,7 +241,7 @@ public function match(string $regexp, int $flags = 0, int $offset = 0): array $regexp .= 'i'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { @@ -300,7 +305,7 @@ public function replaceMatches(string $fromRegexp, string|callable $to): static $replace = \is_array($to) || $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (null === $string = $replace($fromRegexp, $to, $this->string)) { @@ -332,10 +337,10 @@ public function reverse(): static return $str; } - public function slice(int $start = 0, int $length = null): static + public function slice(int $start = 0, ?int $length = null): static { $str = clone $this; - $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX); + $str->string = substr($this->string, $start, $length ?? \PHP_INT_MAX); return $str; } @@ -348,7 +353,7 @@ public function snake(): static return $str; } - public function splice(string $replacement, int $start = 0, int $length = null): static + public function splice(string $replacement, int $start = 0, ?int $length = null): static { $str = clone $this; $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); @@ -356,7 +361,7 @@ public function splice(string $replacement, int $start = 0, int $length = null): return $str; } - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (1 > $limit ??= \PHP_INT_MAX) { throw new InvalidArgumentException('Split limit must be a positive integer.'); @@ -402,12 +407,12 @@ public function title(bool $allWords = false): static return $str; } - public function toUnicodeString(string $fromEncoding = null): UnicodeString + public function toUnicodeString(?string $fromEncoding = null): UnicodeString { return new UnicodeString($this->toCodePointString($fromEncoding)->string); } - public function toCodePointString(string $fromEncoding = null): CodePointString + public function toCodePointString(?string $fromEncoding = null): CodePointString { $u = new CodePointString(); @@ -417,7 +422,7 @@ public function toCodePointString(string $fromEncoding = null): CodePointString return $u; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { try { @@ -436,7 +441,7 @@ public function toCodePointString(string $fromEncoding = null): CodePointString } if (!$validEncoding) { - throw new InvalidArgumentException(sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); + throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); } $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252'); diff --git a/app/vendor/symfony/string/CHANGELOG.md b/app/vendor/symfony/string/CHANGELOG.md index 31a3b54db..ff505b149 100644 --- a/app/vendor/symfony/string/CHANGELOG.md +++ b/app/vendor/symfony/string/CHANGELOG.md @@ -1,6 +1,17 @@ CHANGELOG ========= +7.2 +--- + + * Add `TruncateMode` enum to handle more truncate methods + * Add the `AbstractString::kebab()` method + +7.1 +--- + + * Add `localeLower()`, `localeUpper()`, `localeTitle()` methods to `AbstractUnicodeString` + 6.2 --- diff --git a/app/vendor/symfony/string/CodePointString.php b/app/vendor/symfony/string/CodePointString.php index f5c900fb2..337bfc12a 100644 --- a/app/vendor/symfony/string/CodePointString.php +++ b/app/vendor/symfony/string/CodePointString.php @@ -186,7 +186,7 @@ public function replace(string $from, string $to): static return $str; } - public function slice(int $start = 0, int $length = null): static + public function slice(int $start = 0, ?int $length = null): static { $str = clone $this; $str->string = mb_substr($this->string, $start, $length, 'UTF-8'); @@ -194,7 +194,7 @@ public function slice(int $start = 0, int $length = null): static return $str; } - public function splice(string $replacement, int $start = 0, int $length = null): static + public function splice(string $replacement, int $start = 0, ?int $length = null): static { if (!preg_match('//u', $replacement)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); @@ -208,7 +208,7 @@ public function splice(string $replacement, int $start = 0, int $length = null): return $str; } - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (1 > $limit ??= \PHP_INT_MAX) { throw new InvalidArgumentException('Split limit must be a positive integer.'); diff --git a/app/vendor/symfony/string/Inflector/EnglishInflector.php b/app/vendor/symfony/string/Inflector/EnglishInflector.php index 2cd6bb87b..73db80c6f 100644 --- a/app/vendor/symfony/string/Inflector/EnglishInflector.php +++ b/app/vendor/symfony/string/Inflector/EnglishInflector.php @@ -21,12 +21,39 @@ final class EnglishInflector implements InflectorInterface private const PLURAL_MAP = [ // First entry: plural suffix, reversed // Second entry: length of plural suffix - // Third entry: Whether the suffix may succeed a vocal + // Third entry: Whether the suffix may succeed a vowel // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: singular suffix, normal - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - ['a', 1, true, true, ['on', 'um']], + // bacteria (bacterium) + ['airetcab', 8, true, true, 'bacterium'], + + // corpora (corpus) + ['aroproc', 7, true, true, 'corpus'], + + // criteria (criterion) + ['airetirc', 8, true, true, 'criterion'], + + // curricula (curriculum) + ['alucirruc', 9, true, true, 'curriculum'], + + // quora (quorum) + ['arouq', 5, true, true, 'quorum'], + + // genera (genus) + ['areneg', 6, true, true, 'genus'], + + // media (medium) + ['aidem', 5, true, true, 'medium'], + + // memoranda (memorandum) + ['adnaromem', 9, true, true, 'memorandum'], + + // phenomena (phenomenon) + ['anemonehp', 9, true, true, 'phenomenon'], + + // strata (stratum) + ['atarts', 6, true, true, 'stratum'], // nebulae (nebula) ['ea', 2, true, true, 'a'], @@ -97,6 +124,9 @@ final class EnglishInflector implements InflectorInterface // statuses (status) ['sesutats', 8, true, true, 'status'], + // article (articles), ancle (ancles) + ['sel', 3, true, true, 'le'], + // analyses (analysis), ellipses (ellipsis), fungi (fungus), // neuroses (neurosis), theses (thesis), emphases (emphasis), // oases (oasis), crises (crisis), houses (house), bases (base), @@ -141,7 +171,7 @@ final class EnglishInflector implements InflectorInterface // shoes (shoe) ['se', 2, true, true, ['', 'e']], - // status (status) + // status (status) ['sutats', 6, true, true, 'status'], // tags (tag) @@ -162,10 +192,13 @@ final class EnglishInflector implements InflectorInterface private const SINGULAR_MAP = [ // First entry: singular suffix, reversed // Second entry: length of singular suffix - // Third entry: Whether the suffix may succeed a vocal + // Third entry: Whether the suffix may succeed a vowel // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: plural suffix, normal + // axes (axis) + ['sixa', 4, false, false, 'axes'], + // criterion (criteria) ['airetirc', 8, false, false, 'criterion'], @@ -235,7 +268,13 @@ final class EnglishInflector implements InflectorInterface // teeth (tooth) ['htoot', 5, true, true, 'teeth'], - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + // albums (album) + ['mubla', 5, true, true, 'albums'], + + // quorums (quorum) + ['murouq', 6, true, true, ['quora', 'quorums']], + + // bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum) ['mu', 2, true, true, 'a'], // men (man), women (woman) @@ -244,17 +283,11 @@ final class EnglishInflector implements InflectorInterface // people (person) ['nosrep', 6, true, true, ['persons', 'people']], - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - ['noi', 3, true, true, 'ions'], - - // coupon (coupons) - ['nop', 3, true, true, 'pons'], - - // seasons (season), treasons (treason), poisons (poison), lessons (lesson) - ['nos', 3, true, true, 'sons'], + // criteria (criterion) + ['noiretirc', 9, true, true, 'criteria'], - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - ['no', 2, true, true, 'a'], + // phenomena (phenomenon) + ['nonemonehp', 10, true, true, 'phenomena'], // echoes (echo) ['ohce', 4, true, true, 'echoes'], @@ -265,6 +298,9 @@ final class EnglishInflector implements InflectorInterface // atlases (atlas) ['salta', 5, true, true, 'atlases'], + // aliases (alias) + ['saila', 5, true, true, 'aliases'], + // irises (iris) ['siri', 4, true, true, 'irises'], @@ -285,12 +321,21 @@ final class EnglishInflector implements InflectorInterface // circuses (circus) ['suc', 3, true, true, 'cuses'], + // hippocampi (hippocampus) + ['supmacoppih', 11, false, false, 'hippocampi'], + + // campuses (campus) + ['sup', 3, true, true, 'puses'], + // status (status) ['sutats', 6, true, true, ['status', 'statuses']], // conspectuses (conspectus), prospectuses (prospectus) ['sutcep', 6, true, true, 'pectuses'], + // nexuses (nexus) + ['suxen', 5, false, false, 'nexuses'], + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['su', 2, true, true, 'i'], @@ -312,14 +357,14 @@ final class EnglishInflector implements InflectorInterface // indices (index) ['xedni', 5, false, true, ['indicies', 'indexes']], + // fax (faxes, faxxes) + ['xaf', 3, true, true, ['faxes', 'faxxes']], + // boxes (box) ['xo', 2, false, true, 'oxes'], - // indexes (index), matrixes (matrix) - ['x', 1, true, false, ['cies', 'xes']], - - // appendices (appendix) - ['xi', 2, false, true, 'ices'], + // indexes (index), matrixes (matrix), appendices (appendix) + ['x', 1, true, false, ['ces', 'xes']], // babies (baby) ['y', 1, false, true, 'ies'], @@ -343,15 +388,30 @@ final class EnglishInflector implements InflectorInterface // deer 'reed', + // equipment + 'tnempiuqe', + // feedback 'kcabdeef', // fish 'hsif', + // health + 'htlaeh', + + // history + 'yrotsih', + // info 'ofni', + // information + 'noitamrofni', + + // money + 'yenom', + // moose 'esoom', @@ -363,6 +423,15 @@ final class EnglishInflector implements InflectorInterface // species 'seiceps', + + // traffic + 'ciffart', + + // aircraft + 'tfarcria', + + // hardware + 'erawdrah', ]; public function singularize(string $plural): array @@ -396,14 +465,14 @@ public function singularize(string $plural): array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $pluralLength) { - $nextIsVocal = str_contains('aeiou', $lowerPluralRev[$j]); + $nextIsVowel = str_contains('aeiou', $lowerPluralRev[$j]); - if (!$map[2] && $nextIsVocal) { - // suffix may not succeed a vocal but next char is one + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one break; } - if (!$map[3] && !$nextIsVocal) { + if (!$map[3] && !$nextIsVowel) { // suffix may not succeed a consonant but next char is one break; } @@ -473,14 +542,14 @@ public function pluralize(string $singular): array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $singularLength) { - $nextIsVocal = str_contains('aeiou', $lowerSingularRev[$j]); + $nextIsVowel = str_contains('aeiou', $lowerSingularRev[$j]); - if (!$map[2] && $nextIsVocal) { - // suffix may not succeed a vocal but next char is one + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one break; } - if (!$map[3] && !$nextIsVocal) { + if (!$map[3] && !$nextIsVowel) { // suffix may not succeed a consonant but next char is one break; } diff --git a/app/vendor/symfony/string/Inflector/SpanishInflector.php b/app/vendor/symfony/string/Inflector/SpanishInflector.php new file mode 100644 index 000000000..4b98cb627 --- /dev/null +++ b/app/vendor/symfony/string/Inflector/SpanishInflector.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Inflector; + +final class SpanishInflector implements InflectorInterface +{ + /** + * A list of all rules for pluralise. + * + * @see https://www.spanishdict.com/guide/spanish-plural-noun-forms + * @see https://www.rae.es/gram%C3%A1tica/morfolog%C3%ADa/la-formaci%C3%B3n-del-plural-plurales-en-s-y-plurales-en-es-reglas-generales + */ + // First entry: regex + // Second entry: replacement + private const PLURALIZE_REGEXP = [ + // Specials sí, no + ['/(sí|no)$/i', '\1es'], + + // Words ending with vowel must use -s (RAE 3.2a, 3.2c) + ['/(a|e|i|o|u|á|é|í|ó|ú)$/i', '\1s'], + + // Word ending in s or x and the previous letter is accented (RAE 3.2n) + ['/ás$/i', 'ases'], + ['/és$/i', 'eses'], + ['/ís$/i', 'ises'], + ['/ós$/i', 'oses'], + ['/ús$/i', 'uses'], + + // Words ending in -ión must changed to -iones + ['/ión$/i', '\1iones'], + + // Words ending in some consonants must use -es (RAE 3.2k) + ['/(l|r|n|d|j|s|x|ch|y)$/i', '\1es'], + + // Word ending in z, must changed to ces + ['/(z)$/i', 'ces'], + ]; + + /** + * A list of all rules for singularize. + */ + private const SINGULARIZE_REGEXP = [ + // Specials sí, no + ['/(sí|no)es$/i', '\1'], + + // Words ending in -ión must changed to -iones + ['/iones$/i', '\1ión'], + + // Word ending in z, must changed to ces + ['/ces$/i', 'z'], + + // Word ending in s or x and the previous letter is accented (RAE 3.2n) + ['/(\w)ases$/i', '\1ás'], + ['/eses$/i', 'és'], + ['/ises$/i', 'ís'], + ['/(\w{2,})oses$/i', '\1ós'], + ['/(\w)uses$/i', '\1ús'], + + // Words ending in some consonants and -es, must be the consonants + ['/(l|r|n|d|j|s|x|ch|y)e?s$/i', '\1'], + + // Words ended with vowel and s, must be vowel + ['/(a|e|i|o|u|á|é|ó|í|ú)s$/i', '\1'], + ]; + + private const UNINFLECTED_RULES = [ + // Words ending with pies (RAE 3.2n) + '/.*(piés)$/i', + ]; + + private const UNINFLECTED = '/^(lunes|martes|miércoles|jueves|viernes|análisis|torax|yo|pies)$/i'; + + public function singularize(string $plural): array + { + if ($this->isInflectedWord($plural)) { + return [$plural]; + } + + foreach (self::SINGULARIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $plural)) { + return [preg_replace($regexp, $replace, $plural)]; + } + } + + return [$plural]; + } + + public function pluralize(string $singular): array + { + if ($this->isInflectedWord($singular)) { + return [$singular]; + } + + foreach (self::PLURALIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $singular)) { + return [preg_replace($regexp, $replace, $singular)]; + } + } + + return [$singular.'s']; + } + + private function isInflectedWord(string $word): bool + { + foreach (self::UNINFLECTED_RULES as $rule) { + if (1 === preg_match($rule, $word)) { + return true; + } + } + + return 1 === preg_match(self::UNINFLECTED, $word); + } +} diff --git a/app/vendor/symfony/string/LazyString.php b/app/vendor/symfony/string/LazyString.php index 3128ebb36..b86d7337e 100644 --- a/app/vendor/symfony/string/LazyString.php +++ b/app/vendor/symfony/string/LazyString.php @@ -26,7 +26,7 @@ class LazyString implements \Stringable, \JsonSerializable public static function fromCallable(callable|array $callback, mixed ...$arguments): static { if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) instanceof \Closure || 2 < \count($callback))) { - throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); + throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); } $lazyString = new static(); @@ -39,7 +39,7 @@ public static function fromCallable(callable|array $callback, mixed ...$argument $callback[1] ??= '__invoke'; } $value = $callback(...$arguments); - $callback = self::getPrettyName($callback); + $callback = !\is_scalar($value) && !$value instanceof \Stringable ? self::getPrettyName($callback) : 'callable'; $arguments = null; } @@ -94,7 +94,7 @@ public function __toString(): string $r = new \ReflectionFunction($this->value); $callback = $r->getStaticVariables()['callback']; - $e = new \TypeError(sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); + $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); } throw $e; @@ -129,7 +129,7 @@ private static function getPrettyName(callable $callback): string } elseif ($callback instanceof \Closure) { $r = new \ReflectionFunction($callback); - if (str_contains($r->name, '{closure}') || !$class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { + if ($r->isAnonymous() || !$class = $r->getClosureCalledClass()) { return $r->name; } diff --git a/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php b/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php index 5a647e67b..6a7509421 100644 --- a/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php +++ b/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php @@ -3,8 +3,8 @@ /* * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.0.0 - * Date: 2022-10-05T17:16:36+02:00 + * Unicode version: 16.0.0 + * Date: 2024-09-11T08:21:22+00:00 */ return [ @@ -44,6 +44,10 @@ 9748, 9749, ], + [ + 9776, + 9783, + ], [ 9800, 9811, @@ -52,6 +56,10 @@ 9855, 9855, ], + [ + 9866, + 9871, + ], [ 9875, 9875, @@ -166,7 +174,7 @@ ], [ 12272, - 12283, + 12287, ], [ 12288, @@ -394,7 +402,11 @@ ], [ 12736, - 12771, + 12773, + ], + [ + 12783, + 12783, ], [ 12784, @@ -448,6 +460,10 @@ 13312, 19903, ], + [ + 19904, + 19967, + ], [ 19968, 40959, @@ -832,6 +848,10 @@ 101120, 101589, ], + [ + 101631, + 101631, + ], [ 101632, 101640, @@ -876,6 +896,14 @@ 110960, 111355, ], + [ + 119552, + 119638, + ], + [ + 119648, + 119670, + ], [ 126980, 126980, @@ -1050,23 +1078,19 @@ ], [ 129664, - 129672, - ], - [ - 129680, - 129725, + 129673, ], [ - 129727, - 129733, + 129679, + 129734, ], [ 129742, - 129755, + 129756, ], [ - 129760, - 129768, + 129759, + 129769, ], [ 129776, @@ -1110,6 +1134,14 @@ ], [ 191457, + 191471, + ], + [ + 191472, + 192093, + ], + [ + 192094, 194559, ], [ diff --git a/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php b/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php index 9ae733032..fdd7f3c7e 100644 --- a/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php +++ b/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php @@ -3,8 +3,8 @@ /* * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.0.0 - * Date: 2022-10-05T17:16:37+02:00 + * Unicode version: 16.0.0 + * Date: 2024-09-11T08:21:22+00:00 */ return [ @@ -109,7 +109,7 @@ 2139, ], [ - 2200, + 2199, 2207, ], [ @@ -916,12 +916,16 @@ 68900, 68903, ], + [ + 68969, + 68973, + ], [ 69291, 69292, ], [ - 69373, + 69372, 69375, ], [ @@ -1044,6 +1048,26 @@ 70512, 70516, ], + [ + 70587, + 70592, + ], + [ + 70606, + 70606, + ], + [ + 70608, + 70608, + ], + [ + 70610, + 70610, + ], + [ + 70625, + 70626, + ], [ 70712, 70719, @@ -1122,6 +1146,10 @@ ], [ 71453, + 71453, + ], + [ + 71455, 71455, ], [ @@ -1276,6 +1304,10 @@ 73538, 73538, ], + [ + 73562, + 73562, + ], [ 78912, 78912, @@ -1284,6 +1316,14 @@ 78919, 78933, ], + [ + 90398, + 90409, + ], + [ + 90413, + 90415, + ], [ 92912, 92916, @@ -1400,6 +1440,10 @@ 124140, 124143, ], + [ + 124398, + 124399, + ], [ 125136, 125142, diff --git a/app/vendor/symfony/string/Slugger/AsciiSlugger.php b/app/vendor/symfony/string/Slugger/AsciiSlugger.php index 6e550c61c..9d4edf15b 100644 --- a/app/vendor/symfony/string/Slugger/AsciiSlugger.php +++ b/app/vendor/symfony/string/Slugger/AsciiSlugger.php @@ -11,7 +11,7 @@ namespace Symfony\Component\String\Slugger; -use Symfony\Component\Intl\Transliterator\EmojiTransliterator; +use Symfony\Component\Emoji\EmojiTransliterator; use Symfony\Component\String\AbstractUnicodeString; use Symfony\Component\String\UnicodeString; use Symfony\Contracts\Translation\LocaleAwareInterface; @@ -55,7 +55,6 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface 'zh' => 'Han-Latin', ]; - private ?string $defaultLocale; private \Closure|array $symbolsMap = [ 'en' => ['@' => 'at', '&' => 'and'], ]; @@ -68,16 +67,14 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface */ private array $transliterators = []; - public function __construct(string $defaultLocale = null, array|\Closure $symbolsMap = null) - { - $this->defaultLocale = $defaultLocale; + public function __construct( + private ?string $defaultLocale = null, + array|\Closure|null $symbolsMap = null, + ) { $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } - /** - * @return void - */ - public function setLocale(string $locale) + public function setLocale(string $locale): void { $this->defaultLocale = $locale; } @@ -95,7 +92,7 @@ public function getLocale(): string public function withEmoji(bool|string $emoji = true): static { if (false !== $emoji && !class_exists(EmojiTransliterator::class)) { - throw new \LogicException(sprintf('You cannot use the "%s()" method as the "symfony/intl" package is not installed. Try running "composer require symfony/intl".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use the "%s()" method as the "symfony/emoji" package is not installed. Try running "composer require symfony/emoji".', __METHOD__)); } $new = clone $this; @@ -104,7 +101,7 @@ public function withEmoji(bool|string $emoji = true): static return $new; } - public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString + public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString { $locale ??= $this->defaultLocale; diff --git a/app/vendor/symfony/string/Slugger/SluggerInterface.php b/app/vendor/symfony/string/Slugger/SluggerInterface.php index c679ed933..dd0d58102 100644 --- a/app/vendor/symfony/string/Slugger/SluggerInterface.php +++ b/app/vendor/symfony/string/Slugger/SluggerInterface.php @@ -23,5 +23,5 @@ interface SluggerInterface /** * Creates a slug for the given string and locale, using appropriate transliteration when needed. */ - public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString; + public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString; } diff --git a/app/vendor/symfony/string/TruncateMode.php b/app/vendor/symfony/string/TruncateMode.php new file mode 100644 index 000000000..12568cd5b --- /dev/null +++ b/app/vendor/symfony/string/TruncateMode.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +enum TruncateMode +{ + /** + * Will cut exactly at given length. + * + * Length: 14 + * Source: Lorem ipsum dolor sit amet + * Output: Lorem ipsum do + */ + case Char; + + /** + * Returns the string up to the last complete word containing the specified length. + * + * Length: 14 + * Source: Lorem ipsum dolor sit amet + * Output: Lorem ipsum + */ + case WordBefore; + + /** + * Returns the string up to the complete word after or at the given length. + * + * Length: 14 + * Source: Lorem ipsum dolor sit amet + * Output: Lorem ipsum dolor + */ + case WordAfter; +} diff --git a/app/vendor/symfony/string/UnicodeString.php b/app/vendor/symfony/string/UnicodeString.php index a64c6a9df..b458de0c5 100644 --- a/app/vendor/symfony/string/UnicodeString.php +++ b/app/vendor/symfony/string/UnicodeString.php @@ -34,23 +34,32 @@ class UnicodeString extends AbstractUnicodeString { public function __construct(string $string = '') { - $this->string = normalizer_is_normalized($string) ? $string : normalizer_normalize($string); + if ('' === $string || normalizer_is_normalized($this->string = $string)) { + return; + } - if (false === $this->string) { + if (false === $string = normalizer_normalize($string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + + $this->string = $string; } public function append(string ...$suffix): static { $str = clone $this; $str->string = $this->string.(1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix)); - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + $str->string = $string; + return $str; } @@ -176,7 +185,7 @@ public function indexOfLast(string|iterable|AbstractString $needle, int $offset return false === $i ? null : $i; } - public function join(array $strings, string $lastGlue = null): static + public function join(array $strings, ?string $lastGlue = null): static { $str = parent::join($strings, $lastGlue); normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); @@ -209,12 +218,17 @@ public function prepend(string ...$prefix): static { $str = clone $this; $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string; - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + $str->string = $string; + return $str; } @@ -235,11 +249,16 @@ public function replace(string $from, string $to): static } $str->string = $result.$tail; - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + + $str->string = $string; } return $str; @@ -253,7 +272,7 @@ public function replaceMatches(string $fromRegexp, string|callable $to): static return $str; } - public function slice(int $start = 0, int $length = null): static + public function slice(int $start = 0, ?int $length = null): static { $str = clone $this; @@ -262,23 +281,28 @@ public function slice(int $start = 0, int $length = null): static return $str; } - public function splice(string $replacement, int $start = 0, int $length = null): static + public function splice(string $replacement, int $start = 0, ?int $length = null): static { $str = clone $this; $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0; - $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; + $length = $length ? \strlen(grapheme_substr($this->string, $start, $length)) : $length; $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647); - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + $str->string = $string; + return $str; } - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (1 > $limit ??= 2147483647) { throw new InvalidArgumentException('Split limit must be a positive integer.'); @@ -338,7 +362,7 @@ public function startsWith(string|iterable|AbstractString $prefix): bool return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); } - public function __wakeup() + public function __wakeup(): void { if (!\is_string($this->string)) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); diff --git a/app/vendor/symfony/string/composer.json b/app/vendor/symfony/string/composer.json index 3545c8531..10d0ee620 100644 --- a/app/vendor/symfony/string/composer.json +++ b/app/vendor/symfony/string/composer.json @@ -16,18 +16,19 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0", - "symfony/intl": "^6.2", - "symfony/http-client": "^5.4|^6.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/emoji": "^7.1", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/var-exporter": "^6.4|^7.0" }, "conflict": { "symfony/translation-contracts": "<2.5" diff --git a/app/vendor/symfony/var-dumper/CHANGELOG.md b/app/vendor/symfony/var-dumper/CHANGELOG.md index 932987501..e47de40cc 100644 --- a/app/vendor/symfony/var-dumper/CHANGELOG.md +++ b/app/vendor/symfony/var-dumper/CHANGELOG.md @@ -1,6 +1,29 @@ CHANGELOG ========= +7.2 +--- + + * Add support for `FORCE_COLOR` environment variable + * Add support for virtual properties + +7.1 +--- + + * Add support for new DOM extension classes in `DOMCaster` + +7.0 +--- + + * Add argument `$label` to `VarDumper::dump()` + * Require explicit argument when calling `VarDumper::setHandler()` + * Remove display of backtrace in `Twig_Template`, only `Twig\Template` is supported + +6.4 +--- + + * Dump uninitialized properties + 6.3 --- diff --git a/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php b/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php index 22026f46a..68b1a65ff 100644 --- a/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php @@ -46,10 +46,7 @@ class AmqpCaster \AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS', ]; - /** - * @return array - */ - public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, bool $isNested) + public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -82,10 +79,7 @@ public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $isNested) + public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -108,10 +102,7 @@ public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $ return $a; } - /** - * @return array - */ - public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNested) + public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -134,10 +125,7 @@ public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNe return $a; } - /** - * @return array - */ - public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool $isNested) + public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -165,10 +153,7 @@ public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/app/vendor/symfony/var-dumper/Caster/ArgsStub.php b/app/vendor/symfony/var-dumper/Caster/ArgsStub.php index 9dc24c1b1..aadd033f3 100644 --- a/app/vendor/symfony/var-dumper/Caster/ArgsStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ArgsStub.php @@ -42,10 +42,9 @@ public function __construct(array $args, string $function, ?string $class) $params[] = $variadic; } if (['...'] === $params) { - $this->dumpKeys = false; - $this->value = $values[0]->value; + parent::__construct($values[0]->value, false); } else { - $this->value = array_combine($params, $values); + parent::__construct(array_combine($params, $values)); } } diff --git a/app/vendor/symfony/var-dumper/Caster/Caster.php b/app/vendor/symfony/var-dumper/Caster/Caster.php index 32c69ee04..cc213ab59 100644 --- a/app/vendor/symfony/var-dumper/Caster/Caster.php +++ b/app/vendor/symfony/var-dumper/Caster/Caster.php @@ -32,6 +32,7 @@ class Caster public const EXCLUDE_EMPTY = 128; public const EXCLUDE_NOT_IMPORTANT = 256; public const EXCLUDE_STRICT = 512; + public const EXCLUDE_UNINITIALIZED = 1024; public const PREFIX_VIRTUAL = "\0~\0"; public const PREFIX_DYNAMIC = "\0+\0"; @@ -39,12 +40,14 @@ class Caster // usage: sprintf(Caster::PATTERN_PRIVATE, $class, $property) public const PATTERN_PRIVATE = "\0%s\0%s"; + private static array $classProperties = []; + /** * Casts objects to arrays and adds the dynamic property prefix. * * @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not */ - public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, string $debugClass = null): array + public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, ?string $debugClass = null): array { if ($hasDebugInfo) { try { @@ -61,20 +64,17 @@ public static function castObject(object $obj, string $class, bool $hasDebugInfo return $a; } + $classProperties = self::$classProperties[$class] ??= self::getClassProperties(new \ReflectionClass($class)); + $a = array_replace($classProperties, $a); + if ($a) { - static $publicProperties = []; $debugClass ??= get_debug_type($obj); $i = 0; $prefixedKeys = []; foreach ($a as $k => $v) { if ("\0" !== ($k[0] ?? '')) { - if (!isset($publicProperties[$class])) { - foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { - $publicProperties[$class][$prop->name] = true; - } - } - if (!isset($publicProperties[$class][$k])) { + if (!isset($classProperties[$k])) { $prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k; } } elseif ($debugClass !== $class && 1 === strpos($k, $class)) { @@ -131,6 +131,8 @@ public static function filter(array $a, int $filter, array $listedProperties = [ $type |= self::EXCLUDE_EMPTY & $filter; } elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) { $type |= self::EXCLUDE_EMPTY & $filter; + } elseif ($v instanceof UninitializedStub) { + $type |= self::EXCLUDE_UNINITIALIZED & $filter; } if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) { $type |= self::EXCLUDE_NOT_IMPORTANT; @@ -169,4 +171,28 @@ public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array return $a; } + + private static function getClassProperties(\ReflectionClass $class): array + { + $classProperties = []; + $className = $class->name; + + if ($parent = $class->getParentClass()) { + $classProperties += self::$classProperties[$parent->name] ??= self::getClassProperties($parent); + } + + foreach ($class->getProperties() as $p) { + if ($p->isStatic()) { + continue; + } + + $classProperties[match (true) { + $p->isPublic() => $p->name, + $p->isProtected() => self::PREFIX_PROTECTED.$p->name, + default => "\0".$className."\0".$p->name, + }] = \PHP_VERSION_ID >= 80400 && $p->isVirtual() ? new VirtualStub($p) : new UninitializedStub($p); + } + + return $classProperties; + } } diff --git a/app/vendor/symfony/var-dumper/Caster/ClassStub.php b/app/vendor/symfony/var-dumper/Caster/ClassStub.php index 86b44dd2a..265baa578 100644 --- a/app/vendor/symfony/var-dumper/Caster/ClassStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ClassStub.php @@ -24,7 +24,7 @@ class ClassStub extends ConstStub * @param string $identifier A PHP identifier, e.g. a class, method, interface, etc. name * @param callable $callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier */ - public function __construct(string $identifier, callable|array|string $callable = null) + public function __construct(string $identifier, callable|array|string|null $callable = null) { $this->value = $identifier; @@ -56,7 +56,7 @@ public function __construct(string $identifier, callable|array|string $callable } if (str_contains($identifier, "@anonymous\0")) { - $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $identifier); + $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $identifier); } if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) { @@ -85,10 +85,7 @@ public function __construct(string $identifier, callable|array|string $callable } } - /** - * @return mixed - */ - public static function wrapCallable(mixed $callable) + public static function wrapCallable(mixed $callable): mixed { if (\is_object($callable) || !\is_callable($callable)) { return $callable; diff --git a/app/vendor/symfony/var-dumper/Caster/ConstStub.php b/app/vendor/symfony/var-dumper/Caster/ConstStub.php index d7d1812bd..587c6c398 100644 --- a/app/vendor/symfony/var-dumper/Caster/ConstStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ConstStub.php @@ -20,7 +20,7 @@ */ class ConstStub extends Stub { - public function __construct(string $name, string|int|float $value = null) + public function __construct(string $name, string|int|float|null $value = null) { $this->class = $name; $this->value = 1 < \func_num_args() ? $value : $name; diff --git a/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php b/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php index 0e4fb363d..5912e13d8 100644 --- a/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php +++ b/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php @@ -18,7 +18,7 @@ */ class CutArrayStub extends CutStub { - public $preservedSubset; + public array $preservedSubset; public function __construct(array $value, array $preservedKeys) { diff --git a/app/vendor/symfony/var-dumper/Caster/CutStub.php b/app/vendor/symfony/var-dumper/Caster/CutStub.php index 772399ef6..6870a9cd2 100644 --- a/app/vendor/symfony/var-dumper/Caster/CutStub.php +++ b/app/vendor/symfony/var-dumper/Caster/CutStub.php @@ -27,7 +27,7 @@ public function __construct(mixed $value) switch (\gettype($value)) { case 'object': $this->type = self::TYPE_OBJECT; - $this->class = $value::class; + $this->class = get_debug_type($value); if ($value instanceof \Closure) { ReflectionCaster::castClosure($value, [], $this, true, Caster::EXCLUDE_VERBOSE); diff --git a/app/vendor/symfony/var-dumper/Caster/DOMCaster.php b/app/vendor/symfony/var-dumper/Caster/DOMCaster.php index d2d3fc129..fa58ec4c3 100644 --- a/app/vendor/symfony/var-dumper/Caster/DOMCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DOMCaster.php @@ -23,7 +23,7 @@ class DOMCaster { private const ERROR_CODES = [ - \DOM_PHP_ERR => 'DOM_PHP_ERR', + 0 => 'DOM_PHP_ERR', \DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR', \DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR', \DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR', @@ -63,10 +63,7 @@ class DOMCaster \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', ]; - /** - * @return array - */ - public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested) + public static function castException(\DOMException|\Dom\Exception $e, array $a, Stub $stub, bool $isNested): array { $k = Caster::PREFIX_PROTECTED.'code'; if (isset($a[$k], self::ERROR_CODES[$a[$k]])) { @@ -76,10 +73,7 @@ public static function castException(\DOMException $e, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castLength($dom, array $a, Stub $stub, bool $isNested) + public static function castLength($dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'length' => $dom->length, @@ -88,10 +82,7 @@ public static function castLength($dom, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested) + public static function castImplementation(\DOMImplementation|\Dom\Implementation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'Core' => '1.0', @@ -101,10 +92,7 @@ public static function castImplementation(\DOMImplementation $dom, array $a, Stu return $a; } - /** - * @return array - */ - public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested) + public static function castNode(\DOMNode|\Dom\Node $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'nodeName' => $dom->nodeName, @@ -116,22 +104,24 @@ public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNes 'lastChild' => new CutStub($dom->lastChild), 'previousSibling' => new CutStub($dom->previousSibling), 'nextSibling' => new CutStub($dom->nextSibling), - 'attributes' => $dom->attributes, 'ownerDocument' => new CutStub($dom->ownerDocument), - 'namespaceURI' => $dom->namespaceURI, - 'prefix' => $dom->prefix, - 'localName' => $dom->localName, 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, 'textContent' => new CutStub($dom->textContent), ]; + if ($dom instanceof \DOMNode || $dom instanceof \Dom\Element) { + $a += [ + 'attributes' => $dom->attributes, + 'namespaceURI' => $dom->namespaceURI, + 'prefix' => $dom->prefix, + 'localName' => $dom->localName, + ]; + } + return $a; } - /** - * @return array - */ - public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, bool $isNested) + public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'nodeName' => $dom->nodeName, @@ -147,25 +137,18 @@ public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub return $a; } - /** - * @return array - */ - public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ 'doctype' => $dom->doctype, 'implementation' => $dom->implementation, 'documentElement' => new CutStub($dom->documentElement), - 'actualEncoding' => $dom->actualEncoding, 'encoding' => $dom->encoding, 'xmlEncoding' => $dom->xmlEncoding, - 'standalone' => $dom->standalone, 'xmlStandalone' => $dom->xmlStandalone, - 'version' => $dom->version, 'xmlVersion' => $dom->xmlVersion, 'strictErrorChecking' => $dom->strictErrorChecking, 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, - 'config' => $dom->config, 'formatOutput' => $dom->formatOutput, 'validateOnParse' => $dom->validateOnParse, 'resolveExternals' => $dom->resolveExternals, @@ -184,10 +167,48 @@ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested) + public static function castXMLDocument(\Dom\XMLDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'inputEncoding' => $dom->inputEncoding, + 'xmlEncoding' => $dom->xmlEncoding, + 'xmlStandalone' => $dom->xmlStandalone, + 'xmlVersion' => $dom->xmlVersion, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + 'formatOutput' => $dom->formatOutput, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $formatOutput = $dom->formatOutput; + $dom->formatOutput = true; + $a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()]; + $dom->formatOutput = $formatOutput; + } + + return $a; + } + + public static function castHTMLDocument(\Dom\HTMLDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'inputEncoding' => $dom->inputEncoding, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $a += [Caster::PREFIX_VIRTUAL.'html' => $dom->saveHTML()]; + } + + return $a; + } + + public static function castCharacterData(\DOMCharacterData|\Dom\CharacterData $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'data' => $dom->data, @@ -197,39 +218,40 @@ public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub return $a; } - /** - * @return array - */ - public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested) + public static function castAttr(\DOMAttr|\Dom\Attr $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, 'specified' => $dom->specified, 'value' => $dom->value, 'ownerElement' => $dom->ownerElement, - 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; + if ($dom instanceof \DOMAttr) { + $a += [ + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + } + return $a; } - /** - * @return array - */ - public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested) + public static function castElement(\DOMElement|\Dom\Element $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'tagName' => $dom->tagName, - 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; + if ($dom instanceof \DOMElement) { + $a += [ + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + } + return $a; } - /** - * @return array - */ - public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested) + public static function castText(\DOMText|\Dom\Text $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'wholeText' => $dom->wholeText, @@ -238,10 +260,7 @@ public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested) + public static function castDocumentType(\DOMDocumentType|\Dom\DocumentType $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, @@ -255,10 +274,7 @@ public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $s return $a; } - /** - * @return array - */ - public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested) + public static function castNotation(\DOMNotation|\Dom\Notation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, @@ -268,27 +284,18 @@ public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested) + public static function castEntity(\DOMEntity|\Dom\Entity $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, 'systemId' => $dom->systemId, 'notationName' => $dom->notationName, - 'actualEncoding' => $dom->actualEncoding, - 'encoding' => $dom->encoding, - 'version' => $dom->version, ]; return $a; } - /** - * @return array - */ - public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested) + public static function castProcessingInstruction(\DOMProcessingInstruction|\Dom\ProcessingInstruction $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'target' => $dom->target, @@ -298,10 +305,7 @@ public static function castProcessingInstruction(\DOMProcessingInstruction $dom, return $a; } - /** - * @return array - */ - public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested) + public static function castXPath(\DOMXPath|\Dom\XPath $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'document' => $dom->document, diff --git a/app/vendor/symfony/var-dumper/Caster/DateCaster.php b/app/vendor/symfony/var-dumper/Caster/DateCaster.php index a0cbddb76..f6c35f2b5 100644 --- a/app/vendor/symfony/var-dumper/Caster/DateCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DateCaster.php @@ -24,10 +24,7 @@ class DateCaster { private const PERIOD_LIMIT = 3; - /** - * @return array - */ - public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, bool $isNested, int $filter) + public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, bool $isNested, int $filter): array { $prefix = Caster::PREFIX_VIRTUAL; $location = $d->getTimezone() ? $d->getTimezone()->getLocation() : null; @@ -50,10 +47,7 @@ public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castInterval(\DateInterval $interval, array $a, Stub $stub, bool $isNested, int $filter) + public static function castInterval(\DateInterval $interval, array $a, Stub $stub, bool $isNested, int $filter): array { $now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC')); $numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp(); @@ -82,10 +76,7 @@ private static function formatInterval(\DateInterval $i): string return $i->format(rtrim($format)); } - /** - * @return array - */ - public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, bool $isNested, int $filter) + public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, bool $isNested, int $filter): array { $location = $timeZone->getLocation(); $formatted = (new \DateTimeImmutable('now', $timeZone))->format($location ? 'e (P)' : 'P'); @@ -96,30 +87,27 @@ public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stu return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a; } - /** - * @return array - */ - public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $isNested, int $filter) + public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $isNested, int $filter): array { $dates = []; foreach (clone $p as $i => $d) { if (self::PERIOD_LIMIT === $i) { $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - $dates[] = sprintf('%s more', ($end = $p->getEndDate()) + $dates[] = \sprintf('%s more', ($end = $p->getEndDate()) ? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u'))) : $p->recurrences - $i ); break; } - $dates[] = sprintf('%s) %s', $i + 1, self::formatDateTime($d)); + $dates[] = \sprintf('%s) %s', $i + 1, self::formatDateTime($d)); } - $period = sprintf( + $period = \sprintf( 'every %s, from %s%s %s', self::formatInterval($p->getDateInterval()), $p->include_start_date ? '[' : ']', self::formatDateTime($p->getStartDate()), - ($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).(\PHP_VERSION_ID >= 80200 && $p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s' + ($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).($p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s' ); $p = [Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates))]; @@ -134,6 +122,6 @@ private static function formatDateTime(\DateTimeInterface $d, string $extra = '' private static function formatSeconds(string $s, string $us): string { - return sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us)); + return \sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us)); } } diff --git a/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php b/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php index 3120c3d91..74c06a416 100644 --- a/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php @@ -25,10 +25,7 @@ */ class DoctrineCaster { - /** - * @return array - */ - public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, bool $isNested) + public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, bool $isNested): array { foreach (['__cloner__', '__initializer__'] as $k) { if (\array_key_exists($k, $a)) { @@ -40,10 +37,7 @@ public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool $isNested) + public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool $isNested): array { foreach (['_entityPersister', '_identifier'] as $k) { if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) { @@ -55,10 +49,7 @@ public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, bool $isNested) + public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, bool $isNested): array { foreach (['snapshot', 'association', 'typeClass'] as $k) { if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) { diff --git a/app/vendor/symfony/var-dumper/Caster/DsPairStub.php b/app/vendor/symfony/var-dumper/Caster/DsPairStub.php index 22112af9c..afa2727b1 100644 --- a/app/vendor/symfony/var-dumper/Caster/DsPairStub.php +++ b/app/vendor/symfony/var-dumper/Caster/DsPairStub.php @@ -18,7 +18,7 @@ */ class DsPairStub extends Stub { - public function __construct(string|int $key, mixed $value) + public function __construct(mixed $key, mixed $value) { $this->value = [ Caster::PREFIX_VIRTUAL.'key' => $key, diff --git a/app/vendor/symfony/var-dumper/Caster/EnumStub.php b/app/vendor/symfony/var-dumper/Caster/EnumStub.php index 7a4e98a21..11e0cd9a1 100644 --- a/app/vendor/symfony/var-dumper/Caster/EnumStub.php +++ b/app/vendor/symfony/var-dumper/Caster/EnumStub.php @@ -20,11 +20,10 @@ */ class EnumStub extends Stub { - public $dumpKeys = true; - - public function __construct(array $values, bool $dumpKeys = true) - { + public function __construct( + array $values, + public bool $dumpKeys = true, + ) { $this->value = $values; - $this->dumpKeys = $dumpKeys; } } diff --git a/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php b/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php index 02efb1b02..fb67a704f 100644 --- a/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php @@ -42,31 +42,22 @@ class ExceptionCaster \E_USER_ERROR => 'E_USER_ERROR', \E_USER_WARNING => 'E_USER_WARNING', \E_USER_NOTICE => 'E_USER_NOTICE', - \E_STRICT => 'E_STRICT', + 2048 => 'E_STRICT', ]; private static array $framesCache = []; - /** - * @return array - */ - public static function castError(\Error $e, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castError(\Error $e, array $a, Stub $stub, bool $isNested, int $filter = 0): array { return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter); } - /** - * @return array - */ - public static function castException(\Exception $e, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castException(\Exception $e, array $a, Stub $stub, bool $isNested, int $filter = 0): array { return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter); } - /** - * @return array - */ - public static function castErrorException(\ErrorException $e, array $a, Stub $stub, bool $isNested) + public static function castErrorException(\ErrorException $e, array $a, Stub $stub, bool $isNested): array { if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) { $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); @@ -75,10 +66,7 @@ public static function castErrorException(\ErrorException $e, array $a, Stub $st return $a; } - /** - * @return array - */ - public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, bool $isNested) + public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, bool $isNested): array { $trace = Caster::PREFIX_VIRTUAL.'trace'; $prefix = Caster::PREFIX_PROTECTED; @@ -96,10 +84,7 @@ public static function castThrowingCasterException(ThrowingCasterException $e, a return $a; } - /** - * @return array - */ - public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, bool $isNested) + public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, bool $isNested): array { $sPrefix = "\0".SilencedErrorContext::class."\0"; @@ -126,10 +111,7 @@ public static function castSilencedErrorContext(SilencedErrorContext $e, array $ return $a; } - /** - * @return array - */ - public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, bool $isNested) + public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, bool $isNested): array { if (!$isNested) { return $a; @@ -192,7 +174,7 @@ public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, boo } else { $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall; } - $a[substr_replace($label, sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame; + $a[substr_replace($label, \sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame; $lastCall = $call; } @@ -203,10 +185,7 @@ public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, bool $isNested) + public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, bool $isNested): array { if (!$isNested) { return $a; @@ -235,12 +214,12 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo $ellipsis = $ellipsis->attr['ellipsis'] ?? 0; if (is_file($f['file']) && 0 <= self::$srcContext) { - if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) { + if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig\Template')) { $template = null; if (isset($f['object'])) { $template = $f['object']; } elseif ((new \ReflectionClass($f['class']))->isInstantiable()) { - $template = unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class'])); + $template = unserialize(\sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class'])); } if (null !== $template) { $ellipsis = 0; @@ -264,7 +243,7 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo $ellipsis += 1 + \strlen($f['line']); } } - $srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); + $srcAttr .= \sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); } else { $srcAttr .= '&separator=:'; } @@ -289,13 +268,10 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castFlattenException(FlattenException $e, array $a, Stub $stub, bool $isNested) + public static function castFlattenException(FlattenException $e, array $a, Stub $stub, bool $isNested): array { if ($isNested) { - $k = sprintf(Caster::PATTERN_PRIVATE, FlattenException::class, 'traceAsString'); + $k = \sprintf(Caster::PATTERN_PRIVATE, FlattenException::class, 'traceAsString'); $a[$k] = new CutStub($a[$k]); } @@ -323,7 +299,7 @@ private static function filterExceptionArray(string $xClass, array $a, string $x unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message']); if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { - $a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $a[Caster::PREFIX_PROTECTED.'message']); + $a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $a[Caster::PREFIX_PROTECTED.'message']); } if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { @@ -411,7 +387,7 @@ private static function extractSource(string $srcLines, int $line, int $srcConte } } $c->attr['lang'] = $lang; - $srcLines[sprintf("\0~separator=› &%d\0", $i + $line - $srcContext)] = $c; + $srcLines[\sprintf("\0~separator=› &%d\0", $i + $line - $srcContext)] = $c; } return new EnumStub($srcLines); diff --git a/app/vendor/symfony/var-dumper/Caster/FFICaster.php b/app/vendor/symfony/var-dumper/Caster/FFICaster.php index 7d90e7b57..973b69689 100644 --- a/app/vendor/symfony/var-dumper/Caster/FFICaster.php +++ b/app/vendor/symfony/var-dumper/Caster/FFICaster.php @@ -41,7 +41,7 @@ public static function castCTypeOrCData(CData|CType $data, array $args, Stub $st $type = \FFI::typeof($data); } - $stub->class = sprintf('%s<%s> size %d align %d', ($data ?? $type)::class, $type->getName(), $type->getSize(), $type->getAlignment()); + $stub->class = \sprintf('%s<%s> size %d align %d', ($data ?? $type)::class, $type->getName(), $type->getSize(), $type->getAlignment()); return match ($type->getKind()) { CType::TYPE_FLOAT, @@ -86,7 +86,7 @@ private static function castFFIFunction(Stub $stub, CType $type): array CType::ABI_MS => '[ms]', CType::ABI_SYSV => '[sysv]', CType::ABI_VECTORCALL => '[vectorcall]', - default => '[unknown abi]' + default => '[unknown abi]', }; $returnType = $type->getFuncReturnType(); @@ -97,7 +97,7 @@ private static function castFFIFunction(Stub $stub, CType $type): array return [Caster::PREFIX_VIRTUAL.'returnType' => $returnType]; } - private static function castFFIPointer(Stub $stub, CType $type, CData $data = null): array + private static function castFFIPointer(Stub $stub, CType $type, ?CData $data = null): array { $ptr = $type->getPointerType(); @@ -115,11 +115,21 @@ private static function castFFIPointer(Stub $stub, CType $type, CData $data = nu private static function castFFIStringValue(CData $data): string|CutStub { $result = []; + $ffi = \FFI::cdef(<<zend_get_page_size(); + + // get cdata address + $start = $ffi->cast('uintptr_t', $ffi->cast('char*', $data))->cdata; + // accessing memory in the same page as $start is safe + $max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start); + + for ($i = 0; $i < $max; ++$i) { $result[$i] = $data[$i]; - if ("\0" === $result[$i]) { + if ("\0" === $data[$i]) { return implode('', $result); } } @@ -132,7 +142,7 @@ private static function castFFIStringValue(CData $data): string|CutStub return $stub; } - private static function castFFIStructLike(CType $type, CData $data = null): array + private static function castFFIStructLike(CType $type, ?CData $data = null): array { $isUnion = ($type->getAttributes() & CType::ATTR_UNION) === CType::ATTR_UNION; diff --git a/app/vendor/symfony/var-dumper/Caster/FiberCaster.php b/app/vendor/symfony/var-dumper/Caster/FiberCaster.php index b797dbd63..c9df7087a 100644 --- a/app/vendor/symfony/var-dumper/Caster/FiberCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/FiberCaster.php @@ -20,10 +20,7 @@ */ final class FiberCaster { - /** - * @return array - */ - public static function castFiber(\Fiber $fiber, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castFiber(\Fiber $fiber, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/app/vendor/symfony/var-dumper/Caster/FrameStub.php b/app/vendor/symfony/var-dumper/Caster/FrameStub.php index 878675528..e57aa4630 100644 --- a/app/vendor/symfony/var-dumper/Caster/FrameStub.php +++ b/app/vendor/symfony/var-dumper/Caster/FrameStub.php @@ -18,13 +18,11 @@ */ class FrameStub extends EnumStub { - public $keepArgs; - public $inTraceStub; - - public function __construct(array $frame, bool $keepArgs = true, bool $inTraceStub = false) - { - $this->value = $frame; - $this->keepArgs = $keepArgs; - $this->inTraceStub = $inTraceStub; + public function __construct( + array $frame, + public bool $keepArgs = true, + public bool $inTraceStub = false, + ) { + parent::__construct($frame); } } diff --git a/app/vendor/symfony/var-dumper/Caster/IntlCaster.php b/app/vendor/symfony/var-dumper/Caster/IntlCaster.php index a4590f4b5..f386c7215 100644 --- a/app/vendor/symfony/var-dumper/Caster/IntlCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/IntlCaster.php @@ -21,10 +21,7 @@ */ class IntlCaster { - /** - * @return array - */ - public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, bool $isNested) + public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), @@ -34,10 +31,7 @@ public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub return self::castError($c, $a); } - /** - * @return array - */ - public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), @@ -114,10 +108,7 @@ public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $ return self::castError($c, $a); } - /** - * @return array - */ - public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, bool $isNested) + public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'display_name' => $c->getDisplayName(), @@ -134,10 +125,7 @@ public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, return self::castError($c, $a); } - /** - * @return array - */ - public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ Caster::PREFIX_VIRTUAL.'type' => $c->getType(), @@ -154,10 +142,7 @@ public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, return self::castError($c, $a); } - /** - * @return array - */ - public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), diff --git a/app/vendor/symfony/var-dumper/Caster/LinkStub.php b/app/vendor/symfony/var-dumper/Caster/LinkStub.php index df95f8b0e..3acd4fd67 100644 --- a/app/vendor/symfony/var-dumper/Caster/LinkStub.php +++ b/app/vendor/symfony/var-dumper/Caster/LinkStub.php @@ -18,12 +18,12 @@ */ class LinkStub extends ConstStub { - public $inVendor = false; + public bool $inVendor = false; private static array $vendorRoots; private static array $composerRoots = []; - public function __construct(string $label, int $line = 0, string $href = null) + public function __construct(string $label, int $line = 0, ?string $href = null) { $this->value = $label; diff --git a/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php b/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php index 2f161e8cb..740785cea 100644 --- a/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php @@ -23,10 +23,7 @@ class MemcachedCaster private static array $optionConstants; private static array $defaultOptions; - /** - * @return array - */ - public static function castMemcached(\Memcached $c, array $a, Stub $stub, bool $isNested) + public static function castMemcached(\Memcached $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'servers' => $c->getServerList(), diff --git a/app/vendor/symfony/var-dumper/Caster/PdoCaster.php b/app/vendor/symfony/var-dumper/Caster/PdoCaster.php index d68eae216..1d364cdf0 100644 --- a/app/vendor/symfony/var-dumper/Caster/PdoCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/PdoCaster.php @@ -59,10 +59,7 @@ class PdoCaster ], ]; - /** - * @return array - */ - public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) + public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested): array { $attr = []; $errmode = $c->getAttribute(\PDO::ATTR_ERRMODE); @@ -111,10 +108,7 @@ public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, bool $isNested) + public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; $a[$prefix.'errorInfo'] = $c->errorInfo(); diff --git a/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php b/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php index 0d8b3d919..3e759f69b 100644 --- a/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php @@ -69,20 +69,14 @@ class PgSqlCaster 'function' => \PGSQL_DIAG_SOURCE_FUNCTION, ]; - /** - * @return array - */ - public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested) + public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested): array { $a['seek position'] = pg_lo_tell($lo); return $a; } - /** - * @return array - */ - public static function castLink($link, array $a, Stub $stub, bool $isNested) + public static function castLink($link, array $a, Stub $stub, bool $isNested): array { $a['status'] = pg_connection_status($link); $a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']); @@ -114,10 +108,7 @@ public static function castLink($link, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castResult($result, array $a, Stub $stub, bool $isNested) + public static function castResult($result, array $a, Stub $stub, bool $isNested): array { $a['num rows'] = pg_num_rows($result); $a['status'] = pg_result_status($result); @@ -140,8 +131,8 @@ public static function castResult($result, array $a, Stub $stub, bool $isNested) for ($i = 0; $i < $fields; ++$i) { $field = [ 'name' => pg_field_name($result, $i), - 'table' => sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)), - 'type' => sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)), + 'table' => \sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)), + 'type' => \sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)), 'nullable' => (bool) pg_field_is_null($result, $i), 'storage' => pg_field_size($result, $i).' bytes', 'display' => pg_field_prtlen($result, $i).' chars', diff --git a/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php b/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php index eb6c88db6..736a6e758 100644 --- a/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php @@ -21,10 +21,7 @@ */ class ProxyManagerCaster { - /** - * @return array - */ - public static function castProxy(ProxyInterface $c, array $a, Stub $stub, bool $isNested) + public static function castProxy(ProxyInterface $c, array $a, Stub $stub, bool $isNested): array { if ($parent = get_parent_class($c)) { $stub->class .= ' - '.$parent; diff --git a/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php b/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php index fcaa1b768..5445b2d4b 100644 --- a/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php @@ -31,10 +31,7 @@ */ class RdKafkaCaster { - /** - * @return array - */ - public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, bool $isNested) + public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -54,10 +51,7 @@ public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) + public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -68,10 +62,7 @@ public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castTopicPartition(TopicPartition $c, array $a) + public static function castTopicPartition(TopicPartition $c, array $a): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -84,10 +75,7 @@ public static function castTopicPartition(TopicPartition $c, array $a) return $a; } - /** - * @return array - */ - public static function castMessage(Message $c, array $a, Stub $stub, bool $isNested) + public static function castMessage(Message $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -98,10 +86,7 @@ public static function castMessage(Message $c, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) + public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -112,10 +97,7 @@ public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $isNested) + public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -126,10 +108,7 @@ public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $i return $a; } - /** - * @return array - */ - public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNested) + public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -142,20 +121,14 @@ public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNe return $a; } - /** - * @return array - */ - public static function castCollectionMetadata(CollectionMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castCollectionMetadata(CollectionMetadata $c, array $a, Stub $stub, bool $isNested): array { $a += iterator_to_array($c); return $a; } - /** - * @return array - */ - public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -167,10 +140,7 @@ public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -183,10 +153,7 @@ public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stu return $a; } - /** - * @return array - */ - public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -199,10 +166,7 @@ public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stu return $a; } - /** - * @return array - */ - private static function extractMetadata(KafkaConsumer|\RdKafka $c) + private static function extractMetadata(KafkaConsumer|\RdKafka $c): array { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/app/vendor/symfony/var-dumper/Caster/RedisCaster.php b/app/vendor/symfony/var-dumper/Caster/RedisCaster.php index 6ff046754..5224bc05d 100644 --- a/app/vendor/symfony/var-dumper/Caster/RedisCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/RedisCaster.php @@ -47,10 +47,7 @@ class RedisCaster \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES', ]; - /** - * @return array - */ - public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $isNested) + public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -76,10 +73,7 @@ public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $is ]; } - /** - * @return array - */ - public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool $isNested) + public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -91,10 +85,7 @@ public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool ]; } - /** - * @return array - */ - public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, bool $isNested) + public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; $failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER); diff --git a/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php b/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php index 4adb9bc9f..e7bd9a152 100644 --- a/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php @@ -35,17 +35,14 @@ class ReflectionCaster 'isVariadic' => 'isVariadic', ]; - /** - * @return array - */ - public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; $c = new \ReflectionFunction($c); $a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter); - if (!str_contains($c->name, '{closure}')) { + if (!$c->isAnonymous()) { $stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name; unset($a[$prefix.'class']); } @@ -74,10 +71,7 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNe return $a; } - /** - * @return array - */ - public static function unsetClosureFileInfo(\Closure $c, array $a) + public static function unsetClosureFileInfo(\Closure $c, array $a): array { unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']); @@ -89,25 +83,22 @@ public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $ // Cannot create ReflectionGenerator based on a terminated Generator try { $reflectionGenerator = new \ReflectionGenerator($c); + + return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } catch (\Exception) { $a[Caster::PREFIX_VIRTUAL.'closed'] = true; return $a; } - - return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } - /** - * @return array - */ - public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested) + public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; if ($c instanceof \ReflectionNamedType) { $a += [ - $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, + $prefix.'name' => $c->getName(), $prefix.'allowsNull' => $c->allowsNull(), $prefix.'isBuiltin' => $c->isBuiltin(), ]; @@ -123,23 +114,23 @@ public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $ return $a; } - /** - * @return array - */ - public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested) + public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested): array { - self::addMap($a, $c, [ + $map = [ 'name' => 'getName', 'arguments' => 'getArguments', - ]); + ]; + + if (\PHP_VERSION_ID >= 80400) { + unset($map['name']); + } + + self::addMap($a, $c, $map); return $a; } - /** - * @return array - */ - public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, bool $isNested) + public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -174,10 +165,7 @@ public static function castReflectionGenerator(\ReflectionGenerator $c, array $a return $a; } - /** - * @return array - */ - public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -208,24 +196,21 @@ public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; self::addMap($a, $c, [ 'returnsReference' => 'returnsReference', 'returnType' => 'getReturnType', - 'class' => \PHP_VERSION_ID >= 80111 ? 'getClosureCalledClass' : 'getClosureScopeClass', + 'class' => 'getClosureCalledClass', 'this' => 'getClosureThis', ]); if (isset($a[$prefix.'returnType'])) { $v = $a[$prefix.'returnType']; $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; - $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); + $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && !\in_array($v, ['mixed', 'null'], true) ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); } if (isset($a[$prefix.'class'])) { $a[$prefix.'class'] = new ClassStub($a[$prefix.'class']); @@ -269,10 +254,7 @@ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, arra return $a; } - /** - * @return array - */ - public static function castClassConstant(\ReflectionClassConstant $c, array $a, Stub $stub, bool $isNested) + public static function castClassConstant(\ReflectionClassConstant $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); $a[Caster::PREFIX_VIRTUAL.'value'] = $c->getValue(); @@ -282,20 +264,14 @@ public static function castClassConstant(\ReflectionClassConstant $c, array $a, return $a; } - /** - * @return array - */ - public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bool $isNested) + public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); return $a; } - /** - * @return array - */ - public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, bool $isNested) + public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -335,10 +311,7 @@ public static function castParameter(\ReflectionParameter $c, array $a, Stub $st return $a; } - /** - * @return array - */ - public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, bool $isNested) + public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); @@ -348,20 +321,14 @@ public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub return $a; } - /** - * @return array - */ - public static function castReference(\ReflectionReference $c, array $a, Stub $stub, bool $isNested) + public static function castReference(\ReflectionReference $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId(); return $a; } - /** - * @return array - */ - public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, bool $isNested) + public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, bool $isNested): array { self::addMap($a, $c, [ 'version' => 'getVersion', @@ -377,10 +344,7 @@ public static function castExtension(\ReflectionExtension $c, array $a, Stub $st return $a; } - /** - * @return array - */ - public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, bool $isNested) + public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, bool $isNested): array { self::addMap($a, $c, [ 'version' => 'getVersion', @@ -392,10 +356,7 @@ public static function castZendExtension(\ReflectionZendExtension $c, array $a, return $a; } - /** - * @return string - */ - public static function getSignature(array $a) + public static function getSignature(array $a): string { $prefix = Caster::PREFIX_VIRTUAL; $signature = ''; @@ -407,7 +368,7 @@ public static function getSignature(array $a) if (!$type instanceof \ReflectionNamedType) { $signature .= $type.' '; } else { - if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) { + if ($param->allowsNull() && !\in_array($type->getName(), ['mixed', 'null'], true)) { $signature .= '?'; } $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' '; diff --git a/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php b/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php index f3bbf3be4..f775f81ca 100644 --- a/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php @@ -27,10 +27,7 @@ public static function castCurl(\CurlHandle $h, array $a, Stub $stub, bool $isNe return curl_getinfo($h); } - /** - * @return array - */ - public static function castDba($dba, array $a, Stub $stub, bool $isNested) + public static function castDba($dba, array $a, Stub $stub, bool $isNested): array { $list = dba_list(); $a['file'] = $list[(int) $dba]; @@ -38,10 +35,7 @@ public static function castDba($dba, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castProcess($process, array $a, Stub $stub, bool $isNested) + public static function castProcess($process, array $a, Stub $stub, bool $isNested): array { return proc_get_status($process); } @@ -56,18 +50,12 @@ public static function castStream($stream, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castStreamContext($stream, array $a, Stub $stub, bool $isNested) + public static function castStreamContext($stream, array $a, Stub $stub, bool $isNested): array { return @stream_context_get_params($stream) ?: $a; } - /** - * @return array - */ - public static function castGd($gd, array $a, Stub $stub, bool $isNested) + public static function castGd($gd, array $a, Stub $stub, bool $isNested): array { $a['size'] = imagesx($gd).'x'.imagesy($gd); $a['trueColor'] = imageistruecolor($gd); @@ -75,10 +63,7 @@ public static function castGd($gd, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested) + public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested): array { $stub->cut = -1; $info = openssl_x509_parse($h, false); diff --git a/app/vendor/symfony/var-dumper/Caster/SplCaster.php b/app/vendor/symfony/var-dumper/Caster/SplCaster.php index 814d824d1..bd2bcc048 100644 --- a/app/vendor/symfony/var-dumper/Caster/SplCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/SplCaster.php @@ -29,26 +29,17 @@ class SplCaster \SplFileObject::READ_CSV => 'READ_CSV', ]; - /** - * @return array - */ - public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested) + public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested): array { return self::castSplArray($c, $a, $stub, $isNested); } - /** - * @return array - */ - public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested) + public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested): array { return self::castSplArray($c, $a, $stub, $isNested); } - /** - * @return array - */ - public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested) + public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c), @@ -57,10 +48,7 @@ public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNest return $a; } - /** - * @return array - */ - public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested) + public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; $mode = $c->getIteratorMode(); @@ -75,10 +63,7 @@ public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, S return $a; } - /** - * @return array - */ - public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested) + public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested): array { static $map = [ 'path' => 'getPath', @@ -141,7 +126,7 @@ public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool } if (isset($a[$prefix.'perms'])) { - $a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']); + $a[$prefix.'perms'] = new ConstStub(\sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']); } static $mapDate = ['aTime', 'mTime', 'cTime']; @@ -154,10 +139,7 @@ public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested) + public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested): array { static $map = [ 'csvControl' => 'getCsvControl', @@ -194,10 +176,7 @@ public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, b return $a; } - /** - * @return array - */ - public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested) + public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested): array { $storage = []; unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967 @@ -208,7 +187,7 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s $storage[] = new EnumStub([ 'object' => $obj, 'info' => $clone->getInfo(), - ]); + ]); } $a += [ @@ -218,30 +197,21 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s return $a; } - /** - * @return array - */ - public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested) + public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator(); return $a; } - /** - * @return array - */ - public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested) + public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get(); return $a; } - /** - * @return array - */ - public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNested) + public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNested): array { $map = []; @@ -249,7 +219,7 @@ public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNe $map[] = new EnumStub([ 'object' => $obj, 'data' => $data, - ]); + ]); } $a += [ diff --git a/app/vendor/symfony/var-dumper/Caster/StubCaster.php b/app/vendor/symfony/var-dumper/Caster/StubCaster.php index 4b93ff76f..56742b018 100644 --- a/app/vendor/symfony/var-dumper/Caster/StubCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/StubCaster.php @@ -22,10 +22,7 @@ */ class StubCaster { - /** - * @return array - */ - public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) + public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $stub->type = $c->type; @@ -46,18 +43,12 @@ public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool $isNested) + public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool $isNested): array { return $isNested ? $c->preservedSubset : $a; } - /** - * @return array - */ - public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) + public static function cutInternals($obj, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $stub->cut += \count($a); @@ -68,10 +59,7 @@ public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNested) + public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $stub->class = $c->dumpKeys ? '' : null; @@ -94,10 +82,7 @@ public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNeste return $a; } - /** - * @return array - */ - public static function castScalar(ScalarStub $scalarStub, array $a, Stub $stub) + public static function castScalar(ScalarStub $scalarStub, array $a, Stub $stub): array { $stub->type = Stub::TYPE_SCALAR; $stub->attr['value'] = $scalarStub->value; diff --git a/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php b/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php index ebc00f90e..d8422e055 100644 --- a/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php @@ -31,10 +31,7 @@ class SymfonyCaster 'format' => 'getRequestFormat', ]; - /** - * @return array - */ - public static function castRequest(Request $request, array $a, Stub $stub, bool $isNested) + public static function castRequest(Request $request, array $a, Stub $stub, bool $isNested): array { $clone = null; @@ -49,12 +46,9 @@ public static function castRequest(Request $request, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castHttpClient($client, array $a, Stub $stub, bool $isNested) + public static function castHttpClient($client, array $a, Stub $stub, bool $isNested): array { - $multiKey = sprintf("\0%s\0multi", $client::class); + $multiKey = \sprintf("\0%s\0multi", $client::class); if (isset($a[$multiKey])) { $a[$multiKey] = new CutStub($a[$multiKey]); } @@ -62,10 +56,7 @@ public static function castHttpClient($client, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castHttpClientResponse($response, array $a, Stub $stub, bool $isNested) + public static function castHttpClientResponse($response, array $a, Stub $stub, bool $isNested): array { $stub->cut += \count($a); $a = []; @@ -77,10 +68,7 @@ public static function castHttpClientResponse($response, array $a, Stub $stub, b return $a; } - /** - * @return array - */ - public static function castLazyObjectState($state, array $a, Stub $stub, bool $isNested) + public static function castLazyObjectState($state, array $a, Stub $stub, bool $isNested): array { if (!$isNested) { return $a; @@ -105,10 +93,7 @@ public static function castLazyObjectState($state, array $a, Stub $stub, bool $i return $a; } - /** - * @return array - */ - public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested) + public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $uuid->toBase58(); $a[Caster::PREFIX_VIRTUAL.'toBase32'] = $uuid->toBase32(); @@ -121,10 +106,7 @@ public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested return $a; } - /** - * @return array - */ - public static function castUlid(Ulid $ulid, array $a, Stub $stub, bool $isNested) + public static function castUlid(Ulid $ulid, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $ulid->toBase58(); $a[Caster::PREFIX_VIRTUAL.'toRfc4122'] = $ulid->toRfc4122(); diff --git a/app/vendor/symfony/var-dumper/Caster/TraceStub.php b/app/vendor/symfony/var-dumper/Caster/TraceStub.php index 5eea1c876..b732eb205 100644 --- a/app/vendor/symfony/var-dumper/Caster/TraceStub.php +++ b/app/vendor/symfony/var-dumper/Caster/TraceStub.php @@ -20,17 +20,13 @@ */ class TraceStub extends Stub { - public $keepArgs; - public $sliceOffset; - public $sliceLength; - public $numberingOffset; - - public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, int $sliceLength = null, int $numberingOffset = 0) - { + public function __construct( + array $trace, + public bool $keepArgs = true, + public int $sliceOffset = 0, + public ?int $sliceLength = null, + public int $numberingOffset = 0, + ) { $this->value = $trace; - $this->keepArgs = $keepArgs; - $this->sliceOffset = $sliceOffset; - $this->sliceLength = $sliceLength; - $this->numberingOffset = $numberingOffset; } } diff --git a/app/vendor/symfony/var-dumper/Caster/UninitializedStub.php b/app/vendor/symfony/var-dumper/Caster/UninitializedStub.php new file mode 100644 index 000000000..a9bdd9b81 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/UninitializedStub.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents an uninitialized property. + * + * @author Nicolas Grekas + */ +class UninitializedStub extends ConstStub +{ + public function __construct(\ReflectionProperty $property) + { + parent::__construct('?'.($property->hasType() ? ' '.$property->getType() : ''), 'Uninitialized property'); + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/VirtualStub.php b/app/vendor/symfony/var-dumper/Caster/VirtualStub.php new file mode 100644 index 000000000..60b58faa1 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/VirtualStub.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +class VirtualStub extends ConstStub +{ + public function __construct(\ReflectionProperty $property) + { + parent::__construct('~'.($property->hasType() ? ' '.$property->getType() : ''), 'Virtual property'); + $this->attr['virtual'] = true; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php b/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php index d802bbf2a..672fec68f 100644 --- a/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php @@ -43,10 +43,7 @@ class XmlReaderCaster \XMLReader::XML_DECLARATION => 'XML_DECLARATION', ]; - /** - * @return array - */ - public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, bool $isNested) + public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, bool $isNested): array { try { $properties = [ @@ -85,6 +82,7 @@ public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, b $info[$props]->cut = $count; } + $a = Caster::filter($a, Caster::EXCLUDE_UNINITIALIZED, [], $count); $info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count); // +2 because hasValue and hasAttributes are always filtered $stub->cut += $count + 2; diff --git a/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php b/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php index 0cf42584a..fd3d3a2ab 100644 --- a/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php @@ -47,10 +47,7 @@ class XmlResourceCaster \XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING', ]; - /** - * @return array - */ - public static function castXml($h, array $a, Stub $stub, bool $isNested) + public static function castXml($h, array $a, Stub $stub, bool $isNested): array { $a['current_byte_index'] = xml_get_current_byte_index($h); $a['current_column_number'] = xml_get_current_column_number($h); diff --git a/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php b/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php index 6a746b88e..3cd46942b 100644 --- a/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php +++ b/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php @@ -21,7 +21,7 @@ */ abstract class AbstractCloner implements ClonerInterface { - public static $defaultCasters = [ + public static array $defaultCasters = [ '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], @@ -54,23 +54,38 @@ abstract class AbstractCloner implements ClonerInterface 'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], + 'Dom\Exception' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], + 'Dom\Implementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], 'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], + 'Dom\Node' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], 'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'], 'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'], + 'Dom\XMLDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXMLDocument'], + 'Dom\HTMLDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castHTMLDocument'], 'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'Dom\NodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'Dom\DTDNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], + 'Dom\CharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], 'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], + 'Dom\Attr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], 'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], + 'Dom\Element' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], 'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], + 'Dom\Text' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], 'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], + 'Dom\DocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], 'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], + 'Dom\Notation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], 'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], + 'Dom\Entity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], 'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], + 'Dom\ProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], 'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'], 'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'], @@ -85,6 +100,8 @@ abstract class AbstractCloner implements ClonerInterface 'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpClient\Response\AmpResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpClient\Response\AmpResponseV4' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpClient\Response\AmpResponseV5' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'], @@ -197,9 +214,9 @@ abstract class AbstractCloner implements ClonerInterface 'FFI\CType' => ['Symfony\Component\VarDumper\Caster\FFICaster', 'castCTypeOrCData'], ]; - protected $maxItems = 2500; - protected $maxString = -1; - protected $minDepth = 1; + protected int $maxItems = 2500; + protected int $maxString = -1; + protected int $minDepth = 1; /** * @var array> @@ -219,7 +236,7 @@ abstract class AbstractCloner implements ClonerInterface * * @see addCasters */ - public function __construct(array $casters = null) + public function __construct(?array $casters = null) { $this->addCasters($casters ?? static::$defaultCasters); } @@ -233,10 +250,8 @@ public function __construct(array $casters = null) * see e.g. static::$defaultCasters. * * @param callable[] $casters A map of casters - * - * @return void */ - public function addCasters(array $casters) + public function addCasters(array $casters): void { foreach ($casters as $type => $callback) { $this->casters[$type][] = $callback; @@ -245,20 +260,16 @@ public function addCasters(array $casters) /** * Sets the maximum number of items to clone past the minimum depth in nested structures. - * - * @return void */ - public function setMaxItems(int $maxItems) + public function setMaxItems(int $maxItems): void { $this->maxItems = $maxItems; } /** * Sets the maximum cloned length for strings. - * - * @return void */ - public function setMaxString(int $maxString) + public function setMaxString(int $maxString): void { $this->maxString = $maxString; } @@ -266,10 +277,8 @@ public function setMaxString(int $maxString) /** * Sets the minimum tree depth where we are guaranteed to clone all the items. After this * depth is reached, only setMaxItems items will be cloned. - * - * @return void */ - public function setMinDepth(int $minDepth) + public function setMinDepth(int $minDepth): void { $this->minDepth = $minDepth; } diff --git a/app/vendor/symfony/var-dumper/Cloner/Cursor.php b/app/vendor/symfony/var-dumper/Cloner/Cursor.php index 1fd796d67..8923007ff 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Cursor.php +++ b/app/vendor/symfony/var-dumper/Cloner/Cursor.php @@ -23,21 +23,21 @@ class Cursor public const HASH_OBJECT = Stub::TYPE_OBJECT; public const HASH_RESOURCE = Stub::TYPE_RESOURCE; - public $depth = 0; - public $refIndex = 0; - public $softRefTo = 0; - public $softRefCount = 0; - public $softRefHandle = 0; - public $hardRefTo = 0; - public $hardRefCount = 0; - public $hardRefHandle = 0; - public $hashType; - public $hashKey; - public $hashKeyIsBinary; - public $hashIndex = 0; - public $hashLength = 0; - public $hashCut = 0; - public $stop = false; - public $attr = []; - public $skipChildren = false; + public int $depth = 0; + public int $refIndex = 0; + public int $softRefTo = 0; + public int $softRefCount = 0; + public int $softRefHandle = 0; + public int $hardRefTo = 0; + public int $hardRefCount = 0; + public int $hardRefHandle = 0; + public int $hashType; + public string|int|null $hashKey = null; + public bool $hashKeyIsBinary; + public int $hashIndex = 0; + public int $hashLength = 0; + public int $hashCut = 0; + public bool $stop = false; + public array $attr = []; + public bool $skipChildren = false; } diff --git a/app/vendor/symfony/var-dumper/Cloner/Data.php b/app/vendor/symfony/var-dumper/Cloner/Data.php index 928f72d7a..21e2caa72 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Data.php +++ b/app/vendor/symfony/var-dumper/Cloner/Data.php @@ -17,7 +17,7 @@ /** * @author Nicolas Grekas */ -class Data implements \ArrayAccess, \Countable, \IteratorAggregate +class Data implements \ArrayAccess, \Countable, \IteratorAggregate, \Stringable { private array $data; private int $position = 0; @@ -115,13 +115,13 @@ public function count(): int public function getIterator(): \Traversable { if (!\is_array($value = $this->getValue())) { - throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value))); + throw new \LogicException(\sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value))); } yield from $value; } - public function __get(string $key) + public function __get(string $key): mixed { if (null !== $data = $this->seek($key)) { $item = $this->getStub($data->data[$data->position][$data->key]); @@ -165,7 +165,7 @@ public function __toString(): string return (string) $value; } - return sprintf('%s (count=%d)', $this->getType(), \count($value)); + return \sprintf('%s (count=%d)', $this->getType(), \count($value)); } /** @@ -262,10 +262,8 @@ public function seek(string|int $key): ?static /** * Dumps data with a DumperInterface dumper. - * - * @return void */ - public function dump(DumperInterface $dumper) + public function dump(DumperInterface $dumper): void { $refs = [0]; $cursor = new Cursor(); @@ -372,7 +370,7 @@ private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, break; default: - throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type)); + throw new \RuntimeException(\sprintf('Unexpected Stub type: "%s".', $item->type)); } } elseif ('array' === $type) { $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false); diff --git a/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php b/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php index 4c5b315b6..10f2da08a 100644 --- a/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php +++ b/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php @@ -20,10 +20,8 @@ interface DumperInterface { /** * Dumps a scalar value. - * - * @return void */ - public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value); + public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value): void; /** * Dumps a string. @@ -31,10 +29,8 @@ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|n * @param string $str The string being dumped * @param bool $bin Whether $str is UTF-8 or binary encoded * @param int $cut The number of characters $str has been cut by - * - * @return void */ - public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut): void; /** * Dumps while entering an hash. @@ -42,10 +38,8 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); * @param int $type A Cursor::HASH_* const for the type of hash * @param string|int|null $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item - * - * @return void */ - public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild); + public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild): void; /** * Dumps while leaving an hash. @@ -54,8 +48,6 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo * @param string|int|null $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by - * - * @return void */ - public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut); + public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut): void; } diff --git a/app/vendor/symfony/var-dumper/Cloner/Internal/NoDefault.php b/app/vendor/symfony/var-dumper/Cloner/Internal/NoDefault.php new file mode 100644 index 000000000..ed9db9884 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Cloner/Internal/NoDefault.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner\Internal; + +/** + * Flags a typed property that has no default value. + * + * This dummy object is used to distinguish a property with a default value of null + * from a property that is uninitialized by default. + * + * @internal + */ +enum NoDefault +{ + case NoDefault; +} diff --git a/app/vendor/symfony/var-dumper/Cloner/Stub.php b/app/vendor/symfony/var-dumper/Cloner/Stub.php index 0c2a4b9d0..4455a362b 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Stub.php +++ b/app/vendor/symfony/var-dumper/Cloner/Stub.php @@ -11,6 +11,8 @@ namespace Symfony\Component\VarDumper\Cloner; +use Symfony\Component\VarDumper\Cloner\Internal\NoDefault; + /** * Represents the main properties of a PHP variable. * @@ -31,14 +33,14 @@ class Stub public const ARRAY_ASSOC = 1; public const ARRAY_INDEXED = 2; - public $type = self::TYPE_REF; - public $class = ''; - public $value; - public $cut = 0; - public $handle = 0; - public $refCount = 0; - public $position = 0; - public $attr = []; + public int $type = self::TYPE_REF; + public string|int|null $class = ''; + public mixed $value = null; + public int $cut = 0; + public int $handle = 0; + public int $refCount = 0; + public int $position = 0; + public array $attr = []; private static array $defaultProperties = []; @@ -50,15 +52,20 @@ public function __sleep(): array $properties = []; if (!isset(self::$defaultProperties[$c = static::class])) { - self::$defaultProperties[$c] = get_class_vars($c); + $reflection = new \ReflectionClass($c); + self::$defaultProperties[$c] = []; + + foreach ($reflection->getProperties() as $p) { + if ($p->isStatic()) { + continue; + } - foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) { - unset(self::$defaultProperties[$c][$k]); + self::$defaultProperties[$c][$p->name] = $p->hasDefaultValue() ? $p->getDefaultValue() : ($p->hasType() ? NoDefault::NoDefault : null); } } foreach (self::$defaultProperties[$c] as $k => $v) { - if ($this->$k !== $v) { + if (NoDefault::NoDefault === $v || $this->$k !== $v) { $properties[] = $k; } } diff --git a/app/vendor/symfony/var-dumper/Cloner/VarCloner.php b/app/vendor/symfony/var-dumper/Cloner/VarCloner.php index e168d0d3b..170c8b40a 100644 --- a/app/vendor/symfony/var-dumper/Cloner/VarCloner.php +++ b/app/vendor/symfony/var-dumper/Cloner/VarCloner.php @@ -42,7 +42,6 @@ protected function doClone(mixed $var): array $arrayStub = new Stub(); $arrayStub->type = Stub::TYPE_ARRAY; - $fromObjCast = false; for ($i = 0; $i < $len; ++$i) { // Detect when we move on to the next tree depth @@ -213,24 +212,6 @@ protected function doClone(mixed $var): array } } - if ($fromObjCast) { - $fromObjCast = false; - $refs = $vals; - $vals = []; - $j = -1; - foreach ($queue[$i] as $k => $v) { - foreach ([$k => true] as $gk => $gv) { - } - if ($gk !== $k) { - $vals = (object) $vals; - $vals->{$k} = $refs[++$j]; - $vals = (array) $vals; - } else { - $vals[$k] = $refs[++$j]; - } - } - } - $queue[$i] = $vals; } diff --git a/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php b/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php index 4450fe986..24590fc85 100644 --- a/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php +++ b/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php @@ -26,12 +26,11 @@ */ class CliDescriptor implements DumpDescriptorInterface { - private CliDumper $dumper; private mixed $lastIdentifier = null; - public function __construct(CliDumper $dumper) - { - $this->dumper = $dumper; + public function __construct( + private CliDumper $dumper, + ) { } public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void @@ -47,7 +46,7 @@ public function describe(OutputInterface $output, Data $data, array $context, in if (isset($context['request'])) { $request = $context['request']; $this->lastIdentifier = $request['identifier']; - $section = sprintf('%s %s', $request['method'], $request['uri']); + $section = \sprintf('%s %s', $request['method'], $request['uri']); if ($controller = $request['controller']) { $rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")]; } @@ -62,9 +61,9 @@ public function describe(OutputInterface $output, Data $data, array $context, in if (isset($context['source'])) { $source = $context['source']; - $sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']); + $sourceInfo = \sprintf('%s on line %d', $source['name'], $source['line']); if ($fileLink = $source['file_link'] ?? null) { - $sourceInfo = sprintf('%s', $fileLink, $sourceInfo); + $sourceInfo = \sprintf('%s', $fileLink, $sourceInfo); } $rows[] = ['source', $sourceInfo]; $file = $source['file_relative'] ?? $source['file']; diff --git a/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php b/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php index 98f150a5e..ab9cd4d6d 100644 --- a/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php +++ b/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php @@ -24,12 +24,11 @@ */ class HtmlDescriptor implements DumpDescriptorInterface { - private HtmlDumper $dumper; private bool $initialized = false; - public function __construct(HtmlDumper $dumper) - { - $this->dumper = $dumper; + public function __construct( + private HtmlDumper $dumper, + ) { } public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void @@ -45,22 +44,22 @@ public function describe(OutputInterface $output, Data $data, array $context, in if (isset($context['request'])) { $request = $context['request']; $controller = "{$this->dumper->dump($request['controller'], true, ['maxDepth' => 0])}"; - $title = sprintf('%s %s', $request['method'], $uri = $request['uri'], $uri); + $title = \sprintf('%s %s', $request['method'], $uri = $request['uri'], $uri); $dedupIdentifier = $request['identifier']; } elseif (isset($context['cli'])) { $title = '$ '.$context['cli']['command_line']; $dedupIdentifier = $context['cli']['identifier']; } else { - $dedupIdentifier = uniqid('', true); + $dedupIdentifier = bin2hex(random_bytes(4)); } $sourceDescription = ''; if (isset($context['source'])) { $source = $context['source']; $projectDir = $source['project_dir'] ?? null; - $sourceDescription = sprintf('%s on line %d', $source['name'], $source['line']); + $sourceDescription = \sprintf('%s on line %d', $source['name'], $source['line']); if (isset($source['file_link'])) { - $sourceDescription = sprintf('%s', $source['file_link'], $sourceDescription); + $sourceDescription = \sprintf('%s', $source['file_link'], $sourceDescription); } } @@ -105,7 +104,7 @@ private function renderTags(array $tags): string $renderedTags = ''; foreach ($tags as $key => $value) { - $renderedTags .= sprintf('
  • %s%s
  • ', $key, $value); + $renderedTags .= \sprintf('
  • %s%s
  • ', $key, $value); } return <<server = $server; + public function __construct( + private DumpServer $server, + array $descriptors = [], + ) { $this->descriptors = $descriptors + [ 'cli' => new CliDescriptor(new CliDumper()), 'html' => new HtmlDescriptor(new HtmlDumper()), @@ -57,7 +56,7 @@ public function __construct(DumpServer $server, array $descriptors = []) protected function configure(): void { $this - ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', implode(', ', $this->getAvailableFormats())), 'cli') + ->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format (%s)', implode(', ', $this->getAvailableFormats())), 'cli') ->setHelp(<<<'EOF' %command.name% starts a dump server that collects and displays dumps in a single place for debugging you application: @@ -80,7 +79,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $format = $input->getOption('format'); if (!$descriptor = $this->descriptors[$format] ?? null) { - throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $format)); + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $format)); } $errorIo = $io->getErrorStyle(); @@ -88,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->server->start(); - $errorIo->success(sprintf('Server listening on %s', $this->server->getHost())); + $errorIo->success(\sprintf('Server listening on %s', $this->server->getHost())); $errorIo->comment('Quit the server with CONTROL-C.'); $this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) { diff --git a/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php b/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php index 053a90972..c7a4c8c3b 100644 --- a/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php @@ -26,14 +26,16 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface public const DUMP_COMMA_SEPARATOR = 4; public const DUMP_TRAILING_COMMA = 8; + /** @var callable|resource|string|null */ public static $defaultOutput = 'php://output'; - protected $line = ''; + protected string $line = ''; + /** @var callable|null */ protected $lineDumper; + /** @var resource|null */ protected $outputStream; - protected $decimalPoint = '.'; - protected $indentPad = ' '; - protected $flags; + protected string $decimalPoint = '.'; + protected string $indentPad = ' '; private string $charset = ''; @@ -42,9 +44,11 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface * @param string|null $charset The default character encoding to use for non-UTF8 strings * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation */ - public function __construct($output = null, string $charset = null, int $flags = 0) - { - $this->flags = $flags; + public function __construct( + $output = null, + ?string $charset = null, + protected int $flags = 0, + ) { $this->setCharset($charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'); $this->setOutput($output ?: static::$defaultOutput); if (!$output && \is_string(static::$defaultOutput)) { @@ -55,9 +59,9 @@ public function __construct($output = null, string $charset = null, int $flags = /** * Sets the output destination of the dumps. * - * @param callable|resource|string $output A line dumper callable, an opened stream or an output path + * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path * - * @return callable|resource|string The previous output destination + * @return callable|resource|string|null The previous output destination */ public function setOutput($output) { @@ -87,7 +91,7 @@ public function setCharset(string $charset): string $prev = $this->charset; $charset = strtoupper($charset); - $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; + $charset = 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; $this->charset = $charset; @@ -155,10 +159,8 @@ public function dump(Data $data, $output = null): ?string * * @param int $depth The recursive depth in the dumped structure for the line being dumped, * or -1 to signal the end-of-dump to the line dumper callable - * - * @return void */ - protected function dumpLine(int $depth) + protected function dumpLine(int $depth): void { ($this->lineDumper)($this->line, $depth, $this->indentPad); $this->line = ''; @@ -166,10 +168,8 @@ protected function dumpLine(int $depth) /** * Generic line dumper callback. - * - * @return void */ - protected function echoLine(string $line, int $depth, string $indentPad) + protected function echoLine(string $line, int $depth, string $indentPad): void { if (-1 !== $depth) { fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n"); diff --git a/app/vendor/symfony/var-dumper/Dumper/CliDumper.php b/app/vendor/symfony/var-dumper/Dumper/CliDumper.php index b3358f515..c6dd88c45 100644 --- a/app/vendor/symfony/var-dumper/Dumper/CliDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/CliDumper.php @@ -11,6 +11,7 @@ namespace Symfony\Component\VarDumper\Dumper; +use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter; use Symfony\Component\VarDumper\Cloner\Cursor; use Symfony\Component\VarDumper\Cloner\Stub; @@ -21,29 +22,31 @@ */ class CliDumper extends AbstractDumper { - public static $defaultColors; + public static bool $defaultColors; + /** @var callable|resource|string|null */ public static $defaultOutput = 'php://stdout'; - protected $colors; - protected $maxStringWidth = 0; - protected $styles = [ + protected bool $colors; + protected int $maxStringWidth = 0; + protected array $styles = [ // See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 'default' => '0;38;5;208', 'num' => '1;38;5;38', 'const' => '1;38;5;208', + 'virtual' => '3', 'str' => '1;38;5;113', 'note' => '38;5;38', 'ref' => '38;5;247', - 'public' => '', - 'protected' => '', - 'private' => '', + 'public' => '39', + 'protected' => '39', + 'private' => '39', 'meta' => '38;5;170', 'key' => '38;5;113', 'index' => '38;5;38', ]; - protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/'; - protected static $controlCharsMap = [ + protected static string $controlCharsRx = '/[\x00-\x1F\x7F]+/'; + protected static array $controlCharsMap = [ "\t" => '\t', "\n" => '\n', "\v" => '\v', @@ -51,10 +54,10 @@ class CliDumper extends AbstractDumper "\r" => '\r', "\033" => '\e', ]; - protected static $unicodeCharsRx = "/[\u{00A0}\u{00AD}\u{034F}\u{061C}\u{115F}\u{1160}\u{17B4}\u{17B5}\u{180E}\u{2000}-\u{200F}\u{202F}\u{205F}\u{2060}-\u{2064}\u{206A}-\u{206F}\u{3000}\u{2800}\u{3164}\u{FEFF}\u{FFA0}\u{1D159}\u{1D173}-\u{1D17A}]/u"; + protected static string $unicodeCharsRx = "/[\u{00A0}\u{00AD}\u{034F}\u{061C}\u{115F}\u{1160}\u{17B4}\u{17B5}\u{180E}\u{2000}-\u{200F}\u{202F}\u{205F}\u{2060}-\u{2064}\u{206A}-\u{206F}\u{3000}\u{2800}\u{3164}\u{FEFF}\u{FFA0}\u{1D159}\u{1D173}-\u{1D17A}]/u"; - protected $collapseNextHash = false; - protected $expandNextHash = false; + protected bool $collapseNextHash = false; + protected bool $expandNextHash = false; private array $displayOptions = [ 'fileLinkFormat' => null, @@ -62,7 +65,7 @@ class CliDumper extends AbstractDumper private bool $handlesHrefGracefully; - public function __construct($output = null, string $charset = null, int $flags = 0) + public function __construct($output = null, ?string $charset = null, int $flags = 0) { parent::__construct($output, $charset, $flags); @@ -81,25 +84,21 @@ public function __construct($output = null, string $charset = null, int $flags = ]); } - $this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'; + $this->displayOptions['fileLinkFormat'] = class_exists(FileLinkFormatter::class) ? new FileLinkFormatter() : (\ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'); } /** * Enables/disables colored output. - * - * @return void */ - public function setColors(bool $colors) + public function setColors(bool $colors): void { $this->colors = $colors; } /** * Sets the maximum number of characters per line for dumped strings. - * - * @return void */ - public function setMaxStringWidth(int $maxStringWidth) + public function setMaxStringWidth(int $maxStringWidth): void { $this->maxStringWidth = $maxStringWidth; } @@ -108,10 +107,8 @@ public function setMaxStringWidth(int $maxStringWidth) * Configures styles. * * @param array $styles A map of style names to style definitions - * - * @return void */ - public function setStyles(array $styles) + public function setStyles(array $styles): void { $this->styles = $styles + $this->styles; } @@ -120,18 +117,13 @@ public function setStyles(array $styles) * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior - * - * @return void */ - public function setDisplayOptions(array $displayOptions) + public function setDisplayOptions(array $displayOptions): void { $this->displayOptions = $displayOptions + $this->displayOptions; } - /** - * @return void - */ - public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value) + public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value): void { $this->dumpKey($cursor); $this->collapseNextHash = $this->expandNextHash = false; @@ -192,10 +184,7 @@ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|n $this->endValue($cursor); } - /** - * @return void - */ - public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut): void { $this->dumpKey($cursor); $this->collapseNextHash = $this->expandNextHash = false; @@ -284,10 +273,7 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) } } - /** - * @return void - */ - public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild) + public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild): void { $this->colors ??= $this->supportsColors(); @@ -324,10 +310,7 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo } } - /** - * @return void - */ - public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut) + public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut): void { if (empty($cursor->attr['cut_hash'])) { $this->dumpEllipsis($cursor, $hasChild, $cut); @@ -342,10 +325,8 @@ public function leaveHash(Cursor $cursor, int $type, string|int|null $class, boo * * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by - * - * @return void */ - protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) + protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut): void { if ($cut) { $this->line .= ' …'; @@ -360,16 +341,17 @@ protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) /** * Dumps a key in a hash structure. - * - * @return void */ - protected function dumpKey(Cursor $cursor) + protected function dumpKey(Cursor $cursor): void { if (null !== $key = $cursor->hashKey) { if ($cursor->hashKeyIsBinary) { $key = $this->utf8Encode($key); } - $attr = ['binary' => $cursor->hashKeyIsBinary]; + $attr = [ + 'binary' => $cursor->hashKeyIsBinary, + 'virtual' => $cursor->attr['virtual'] ?? false, + ]; $bin = $cursor->hashKeyIsBinary ? 'b' : ''; $style = 'key'; switch ($cursor->hashType) { @@ -393,7 +375,7 @@ protected function dumpKey(Cursor $cursor) // no break case Cursor::HASH_OBJECT: if (!isset($key[0]) || "\0" !== $key[0]) { - $this->line .= '+'.$bin.$this->style('public', $key).': '; + $this->line .= '+'.$bin.$this->style('public', $key, $attr).': '; } elseif (0 < strpos($key, "\0", 1)) { $key = explode("\0", substr($key, 1), 2); @@ -481,7 +463,7 @@ protected function style(string $style, string $value, array $attr = []): string $s = $startCchr; $c = $c[$i = 0]; do { - $s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i])); + $s .= $map[$c[$i]] ?? \sprintf('\x%02X', \ord($c[$i])); } while (isset($c[++$i])); return $s.$endCchr; @@ -528,6 +510,9 @@ protected function style(string $style, string $value, array $attr = []): string if ('label' === $style && '' !== $value) { $value .= ' '; } + if ($this->colors && ($attr['virtual'] ?? false)) { + $value = "\033[{$this->styles['virtual']}m".$value; + } return $value; } @@ -537,7 +522,7 @@ protected function supportsColors(): bool if ($this->outputStream !== static::$defaultOutput) { return $this->hasColorSupport($this->outputStream); } - if (null !== static::$defaultColors) { + if (isset(static::$defaultColors)) { return static::$defaultColors; } if (isset($_SERVER['argv'][1])) { @@ -571,21 +556,15 @@ protected function supportsColors(): bool return static::$defaultColors = $this->hasColorSupport($h); } - /** - * @return void - */ - protected function dumpLine(int $depth, bool $endOfValue = false) + protected function dumpLine(int $depth, bool $endOfValue = false): void { - if ($this->colors) { - $this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); + if ($this->colors ??= $this->supportsColors()) { + $this->line = \sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); } parent::dumpLine($depth); } - /** - * @return void - */ - protected function endValue(Cursor $cursor) + protected function endValue(Cursor $cursor): void { if (-1 === $cursor->hashType) { return; @@ -615,23 +594,39 @@ private function hasColorSupport(mixed $stream): bool } // Follow https://no-color.org/ - if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { + if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) { return false; } - if ('Hyper' === getenv('TERM_PROGRAM')) { + // Follow https://force-color.org/ + if ('' !== (($_SERVER['FORCE_COLOR'] ?? getenv('FORCE_COLOR'))[0] ?? '')) { return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') - && @sapi_windows_vt100_support($stream)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM'); + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@stream_isatty($stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($stream)) { + return true; + } + + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + ) { + return true; + } + + if ('dumb' === $term = (string) getenv('TERM')) { + return false; } - return stream_isatty($stream); + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); } /** @@ -649,7 +644,7 @@ private function isWindowsTrueColor(): bool || 'Hyper' === getenv('TERM_PROGRAM'); if (!$result) { - $version = sprintf( + $version = \sprintf( '%s.%s.%s', PHP_WINDOWS_VERSION_MAJOR, PHP_WINDOWS_VERSION_MINOR, diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php index 69dff067b..deef25241 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php @@ -22,12 +22,11 @@ */ final class RequestContextProvider implements ContextProviderInterface { - private RequestStack $requestStack; private VarCloner $cloner; - public function __construct(RequestStack $requestStack) - { - $this->requestStack = $requestStack; + public function __construct( + private RequestStack $requestStack, + ) { $this->cloner = new VarCloner(); $this->cloner->setMaxItems(0); $this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php index 790285c97..01e730a81 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php @@ -11,7 +11,7 @@ namespace Symfony\Component\VarDumper\Dumper\ContextProvider; -use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; +use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\VarDumper; @@ -25,17 +25,12 @@ */ final class SourceContextProvider implements ContextProviderInterface { - private int $limit; - private ?string $charset; - private ?string $projectDir; - private ?FileLinkFormatter $fileLinkFormatter; - - public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 9) - { - $this->charset = $charset; - $this->projectDir = $projectDir; - $this->fileLinkFormatter = $fileLinkFormatter; - $this->limit = $limit; + public function __construct( + private ?string $charset = null, + private ?string $projectDir = null, + private ?FileLinkFormatter $fileLinkFormatter = null, + private int $limit = 9, + ) { } public function getContext(): ?array diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php b/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php index 84cfb4259..6102c4768 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php @@ -19,22 +19,16 @@ */ class ContextualizedDumper implements DataDumperInterface { - private DataDumperInterface $wrappedDumper; - private array $contextProviders; - /** * @param ContextProviderInterface[] $contextProviders */ - public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders) - { - $this->wrappedDumper = $wrappedDumper; - $this->contextProviders = $contextProviders; + public function __construct( + private DataDumperInterface $wrappedDumper, + private array $contextProviders, + ) { } - /** - * @return string|null - */ - public function dump(Data $data) + public function dump(Data $data): ?string { $context = $data->getContext(); foreach ($this->contextProviders as $contextProvider) { diff --git a/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php b/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php index 8a2570b2c..1f24852c5 100644 --- a/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php @@ -21,6 +21,7 @@ */ class HtmlDumper extends CliDumper { + /** @var callable|resource|string|null */ public static $defaultOutput = 'php://output'; protected static $themes = [ @@ -28,6 +29,7 @@ class HtmlDumper extends CliDumper 'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', + 'virtual' => 'font-style:italic', 'str' => 'font-weight:bold; color:#56DB3A', 'note' => 'color:#1299DA', 'ref' => 'color:#A0A0A0', @@ -44,6 +46,7 @@ class HtmlDumper extends CliDumper 'default' => 'background:none; color:#CC7832; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', + 'virtual' => 'font-style:italic', 'str' => 'font-weight:bold; color:#629755;', 'note' => 'color:#6897BB', 'ref' => 'color:#6E6E6E', @@ -58,14 +61,13 @@ class HtmlDumper extends CliDumper ], ]; - protected $dumpHeader; - protected $dumpPrefix = '
    ';
    -    protected $dumpSuffix = '
    '; - protected $dumpId = 'sf-dump'; - protected $colors = true; + protected ?string $dumpHeader = null; + protected string $dumpPrefix = '
    ';
    +    protected string $dumpSuffix = '
    '; + protected string $dumpId; + protected bool $colors = true; protected $headerIsDumped = false; - protected $lastDepth = -1; - protected $styles; + protected int $lastDepth = -1; private array $displayOptions = [ 'maxDepth' => 1, @@ -74,7 +76,7 @@ class HtmlDumper extends CliDumper ]; private array $extraDisplayOptions = []; - public function __construct($output = null, string $charset = null, int $flags = 0) + public function __construct($output = null, ?string $charset = null, int $flags = 0) { AbstractDumper::__construct($output, $charset, $flags); $this->dumpId = 'sf-dump-'.mt_rand(); @@ -82,22 +84,16 @@ public function __construct($output = null, string $charset = null, int $flags = $this->styles = static::$themes['dark'] ?? self::$themes['dark']; } - /** - * @return void - */ - public function setStyles(array $styles) + public function setStyles(array $styles): void { $this->headerIsDumped = false; $this->styles = $styles + $this->styles; } - /** - * @return void - */ - public function setTheme(string $themeName) + public function setTheme(string $themeName): void { if (!isset(static::$themes[$themeName])) { - throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); + throw new \InvalidArgumentException(\sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); } $this->setStyles(static::$themes[$themeName]); @@ -107,10 +103,8 @@ public function setTheme(string $themeName) * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior - * - * @return void */ - public function setDisplayOptions(array $displayOptions) + public function setDisplayOptions(array $displayOptions): void { $this->headerIsDumped = false; $this->displayOptions = $displayOptions + $this->displayOptions; @@ -118,20 +112,16 @@ public function setDisplayOptions(array $displayOptions) /** * Sets an HTML header that will be dumped once in the output stream. - * - * @return void */ - public function setDumpHeader(?string $header) + public function setDumpHeader(?string $header): void { $this->dumpHeader = $header; } /** * Sets an HTML prefix and suffix that will encapse every single dump. - * - * @return void */ - public function setDumpBoundaries(string $prefix, string $suffix) + public function setDumpBoundaries(string $prefix, string $suffix): void { $this->dumpPrefix = $prefix; $this->dumpSuffix = $suffix; @@ -148,10 +138,8 @@ public function dump(Data $data, $output = null, array $extraDisplayOptions = [] /** * Dumps the HTML header. - * - * @return string */ - protected function getDumpHeader() + protected function getDumpHeader(): string { $this->headerIsDumped = $this->outputStream ?? $this->lineDumper; @@ -162,7 +150,6 @@ protected function getDumpHeader() $line = str_replace('{$options}', json_encode($this->displayOptions, \JSON_FORCE_OBJECT), <<<'EOHTML' + + diff --git a/app/vendor/twbs/bootstrap/js/tests/visual/modal.html b/app/vendor/twbs/bootstrap/js/tests/visual/modal.html index 09d42333d..efb5127b5 100644 --- a/app/vendor/twbs/bootstrap/js/tests/visual/modal.html +++ b/app/vendor/twbs/bootstrap/js/tests/visual/modal.html @@ -13,21 +13,25 @@ - + `} /> + + + + + + `} /> + + + + + + + + `} /> + + + + +
    +
    +

    الصناديق المنبثقة

    + دليل الإستخدام +
    + +
    + + انقر لعرض/إخفاء الصندوق المنبثق + + `} /> + + + انبثاق إلى الأعلى + + + + + `} /> +
    +
    +
    +
    +

    شريط التقدم

    + دليل الإستخدام +
    + +
    + +
    0%
    +
    +
    +
    25%
    +
    +
    +
    50%
    +
    +
    +
    75%
    +
    +
    +
    100%
    +
    + `} /> + + +
    +
    +
    +
    +
    +
    + + `} /> + +
    +
    +
    +

    المخطوطة

    + دليل الإستخدام +
    + +
    +
    + +
    +

    @fat

    +

    محتوى لتوضيح كيف تعمل المخطوطة. ببساطة، المخطوطة عبارة عن منشور طويل يحتوي على عدة أقسام، ولديه شريط تنقل يسهل الوصول إلى هذه الأقسام الفرعية.

    +

    @mdo

    +

    بصرف النظر عن تحسيننا جدوى المكيّفات أو عدم تحسينها، فإن الطلب على الطاقة سيزداد. وطبقاً لما جاء في مقالة معهد ماساشوستس للتكنولوجيا، السالف ذكره، ثمَّة أمر يجب عدم إغفاله، وهو كيف أن هذا الطلب سيضغط على نظم توفير الطاقة الحالية. إذ لا بد من إعادة تأهيل كل شبكات الكهرباء، وتوسيعها لتلبية طلب الطاقة في زمن الذروة، خلال موجات الحرارة المتزايدة. فحين يكون الحر شديداً يجنح الناس إلى البقاء في الداخل، وإلى زيادة تشغيل المكيّفات، سعياً إلى جو لطيف وهم يستخدمون أدوات وأجهزة مختلفة أخرى.

    +

    واحد

    +

    وكل هذه الأمور المتزامنة من تشغيل الأجهزة، يزيد الضغط على شبكات الطاقة، كما أسلفنا. لكن مجرد زيادة سعة الشبكة ليس كافياً. إذ لا بد من تطوير الشبكات الذكية التي تستخدم الجسّاسات، ونظم المراقبة، والبرامج الإلكترونية، لتحديد متى يكون الشاغلون في المبنى، ومتى يكون ثمَّة حاجة إلى الطاقة، ومتى تكون الحرارة منخفضة، وبذلك يخرج الناس، فلا يستخدمون كثيراً من الكهرباء.

    +

    اثنان

    +

    مع الأسف، كل هذه الحلول المبتكرة مكلِّفة، وهذا ما يجعلها عديمة الجدوى في نظر بعض الشركات الخاصة والمواطن المتقشّف. إن بعض الأفراد الواعين بيئياً يبذلون قصارى جهدهم في تقليص استهلاكهم من الطاقة، ويعون جيداً أهمية أجهزة التكييف المجدية والأرفق بالبيئة. ولكن جهات كثيرة لن تتحرّك لمجرد حافز سلامة المناخ ووقف هدر الطاقة، ما دامت لا تحركها حوافز قانونية. وعلى الحكومات أن تُقدِم عند الاهتمام بالتغيّر المناخي، على وضع التشريعات المناسبة. فبالنظم والحوافز والدعم، يمكن دفع الشركات إلى اعتماد الحلول الأجدى في مكاتبها.

    +

    ثلاثة

    +

    وكما يتبيّن لنا، من عدد الحلول الملطِّفة للمشكلة، ومن تنوّعها، وهي الحلول التي أسلفنا الحديث عنها، فإن التكنولوجيا التي نحتاج إليها من أجل معالجة هذه التحديات، هي في مدى قدرتنا، لكنها ربما تتطلّب بعض التحسين، ودعماً استثمارياً أكبر!

    +

    ولا مانع من إضافة محتوى آخر ليس تحت أي قسم معين.

    +
    +
    +
    +
    +
    +
    +

    الدوائر المتحركة

    + دليل الإستخدام +
    + +
    + ` +
    + جار التحميل... +
    + `)} /> + + ` +
    + جار التحميل... +
    + `)} /> +
    +
    +
    +
    +

    الإشعارات

    + دليل الإستخدام +
    + +
    + +
    + + Bootstrap + قبل 11 دقيقة + +
    +
    + مرحبًا بالعالم! هذه رسالة إشعار. +
    +
    + `} /> + +
    +
    +
    +

    التلميحات

    + دليل الإستخدام +
    + +
    + تلميح يظهر في الأعلى + + + + + `} /> +
    +
    + + + + + + + diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cheatsheet/cheatsheet.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/cheatsheet.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cheatsheet/cheatsheet.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/cheatsheet.css diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cheatsheet/cheatsheet.js b/app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/cheatsheet.js similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cheatsheet/cheatsheet.js rename to app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/cheatsheet.js diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cheatsheet/cheatsheet.rtl.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/cheatsheet.rtl.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cheatsheet/cheatsheet.rtl.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/cheatsheet.rtl.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/index.astro new file mode 100644 index 000000000..ae2752e0f --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/cheatsheet/index.astro @@ -0,0 +1,1563 @@ +--- +import { getData } from '@libs/data' +import { getVersionedDocsPath } from '@libs/path' +import Example from '@shortcodes/Example.astro' +import Placeholder from '@shortcodes/Placeholder.astro' + +export const title = 'Cheatsheet' +export const extra_css = ['cheatsheet.css'] +export const extra_js = [{ src: 'cheatsheet.js' }] +export const body_class = 'bg-body-tertiary' +--- + +
    +
    +

    + Bootstrap + Cheatsheet +

    + RTL cheatsheet +
    +
    + +
    +
    +

    Contents

    + +
    +
    +

    Typography

    + Documentation +
    + +
    + Display 1

    +

    Display 2

    +

    Display 3

    +

    Display 4

    +

    Display 5

    +

    Display 6

    `} /> + + Heading 1

    +

    Heading 2

    +

    Heading 3

    +

    Heading 4

    +

    Heading 5

    +

    Heading 6

    `} /> + + + This is a lead paragraph. It stands out from regular paragraphs. +

    `} /> + + You can use the mark tag to highlight text.

    +

    This line of text is meant to be treated as deleted text.

    +

    This line of text is meant to be treated as no longer accurate.

    +

    This line of text is meant to be treated as an addition to the document.

    +

    This line of text will render as underlined.

    +

    This line of text is meant to be treated as fine print.

    +

    This line rendered as bold text.

    +

    This line rendered as italicized text.

    `} /> + + `} /> + + +

    A well-known quote, contained in a blockquote element.

    +
    Someone famous in Source Title
    + `} /> + + +
  • This is a list.
  • +
  • It appears completely unstyled.
  • +
  • Structurally, it's still a list.
  • +
  • However, this style only applies to immediate child elements.
  • +
  • Nested lists: +
      +
    • are unaffected by this style
    • +
    • will still show a bullet
    • +
    • and have appropriate left margin
    • +
    +
  • +
  • This may still come in handy in some situations.
  • + `} /> + + +
  • This is a list item.
  • +
  • And another one.
  • +
  • But they're displayed inline.
  • + `} /> +
    +
    + +
    +
    +

    Tables

    + Documentation +
    +
    + + + + # + First + Last + Handle + + + + + 1 + Mark + Otto + @mdo + + + 2 + Jacob + Thornton + @fat + + + 3 + John + Doe + @social + + + `} /> + + + + + # + First + Last + Handle + + + + + 1 + Mark + Otto + @mdo + + + 2 + Jacob + Thornton + @fat + + + 3 + John + Doe + @social + + + `} /> + + + + + Class + Heading + Heading + + + + + Default + Cell + Cell + `, + ...getData('theme-colors').map((themeColor) => ` + ${themeColor.title} + Cell + Cell + `), + ` + `]} /> + + + + + # + First + Last + Handle + + + + + 1 + Mark + Otto + @mdo + + + 2 + Jacob + Thornton + @fat + + + 3 + John + Doe + @social + + + `} /> +
    +
    + +
    +
    +

    Figures

    + Documentation +
    + +
    + + +
    A caption for the above image.
    + `} /> +
    +
    +
    + +
    +

    Forms

    + +
    +
    +

    Overview

    + Documentation +
    + +
    + +
    + + +
    We'll never share your email with anyone else.
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + Radios buttons +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    + + `} /> +
    +
    +
    +
    +

    Disabled forms

    + Documentation +
    + +
    + +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    +
    + Disabled radios buttons +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    + +
    + `} /> +
    +
    +
    +
    +

    Sizing

    + Documentation +
    + +
    + + +
    +
    + +
    +
    + +
    `} /> + + + + +
    + +
    +
    + +
    + `} /> + +
    +
    +
    +

    Input group

    + Documentation +
    + +
    + + @ + +
    +
    + + @example.com +
    + +
    + https://example.com/users/ + +
    +
    + $ + + .00 +
    +
    + With textarea + +
    + `} /> + +
    +
    +
    +

    Floating labels

    + Documentation +
    + +
    + +
    + + +
    +
    + + +
    + + `} /> +
    +
    +
    +
    +

    Validation

    + Documentation +
    + +
    + +
    + + +
    + Looks good! +
    +
    +
    + + +
    + Looks good! +
    +
    +
    + +
    + @ + +
    + Please choose a username. +
    +
    +
    +
    + + +
    + Please provide a valid city. +
    +
    +
    + + +
    + Please select a valid state. +
    +
    +
    + + +
    + Please provide a valid zip. +
    +
    +
    +
    + + +
    + You must agree before submitting. +
    +
    +
    +
    + +
    + + `} /> +
    +
    +
    + +
    +

    Components

    + +
    +
    +

    Accordion

    + Documentation +
    + +
    + +
    +

    + +

    +
    +
    + This is the first item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    +
    +

    + +

    +
    +
    + This is the second item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    +
    +

    + +

    +
    +
    + This is the third item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    +
    + `} /> + +
    +
    +
    +

    Alerts

    + Documentation +
    + +
    + ` + + `)} /> + + +

    Well done!

    +

    Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.

    +
    +

    Whenever you need to, be sure to use margin utilities to keep things nice and tidy.

    +
    + `} /> + +
    +
    +
    +

    Badge

    + Documentation +
    + +
    + Example heading New

    +

    Example heading New

    +

    Example heading New

    +

    Example heading New

    +

    Example heading New

    +

    Example heading New

    +

    Example heading New

    +

    Example heading New

    + `} /> + + ` + ${themeColor.title} + `)} /> +
    +
    + +
    +
    +

    Buttons

    + Documentation +
    +
    + ` + + `), + ``]} /> + + ` + + `)} /> + + Small button + + + `} /> +
    +
    +
    +
    +

    Button group

    + Documentation +
    + +
    + +
    + + + + +
    +
    + + + +
    +
    + +
    +
    + `} /> + +
    +
    +
    +

    Card

    + Documentation +
    + +
    + +
    +
    + +
    +
    Card title
    +

    Some quick example text to build on the card title and make up the bulk of the card's content.

    + Go somewhere +
    +
    +
    +
    +
    +
    + Featured +
    +
    +
    Card title
    +

    Some quick example text to build on the card title and make up the bulk of the card's content.

    + Go somewhere +
    + +
    +
    +
    +
    +
    +
    Card title
    +

    Some quick example text to build on the card title and make up the bulk of the card's content.

    +
    +
      +
    • An item
    • +
    • A second item
    • +
    • A third item
    • +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    Card title
    +

    This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

    +

    Last updated 3 mins ago

    +
    +
    +
    +
    +
    +
    + `} /> + +
    + + + + + + + +
    +
    +

    Popovers

    + Documentation +
    + +
    + Click to toggle popover + `} /> + + + Popover on top + + + + + `} /> +
    +
    +
    +
    +

    Progress

    + Documentation +
    + +
    + +
    0%
    +
    +
    +
    25%
    +
    +
    +
    50%
    +
    +
    +
    75%
    +
    +
    +
    100%
    +
    + `} /> + + +
    +
    +
    +
    +
    +
    + + `} /> + +
    +
    +
    +

    Scrollspy

    + Documentation +
    + +
    +
    + +
    +

    First heading

    +

    This is some placeholder content for the scrollspy page. Note that as you scroll down the page, the appropriate navigation link is highlighted. It's repeated throughout the component example. We keep adding some more example copy here to emphasize the scrolling and highlighting.

    +

    Second heading

    +

    This is some placeholder content for the scrollspy page. Note that as you scroll down the page, the appropriate navigation link is highlighted. It's repeated throughout the component example. We keep adding some more example copy here to emphasize the scrolling and highlighting.

    +

    Third heading

    +

    This is some placeholder content for the scrollspy page. Note that as you scroll down the page, the appropriate navigation link is highlighted. It's repeated throughout the component example. We keep adding some more example copy here to emphasize the scrolling and highlighting.

    +

    Fourth heading

    +

    This is some placeholder content for the scrollspy page. Note that as you scroll down the page, the appropriate navigation link is highlighted. It's repeated throughout the component example. We keep adding some more example copy here to emphasize the scrolling and highlighting.

    +

    Fifth heading

    +

    This is some placeholder content for the scrollspy page. Note that as you scroll down the page, the appropriate navigation link is highlighted. It's repeated throughout the component example. We keep adding some more example copy here to emphasize the scrolling and highlighting.

    +
    +
    +
    +
    +
    +
    +

    Spinners

    + Documentation +
    + +
    + ` +
    + Loading... +
    + `)} /> + + ` +
    + Loading... +
    + `)} /> +
    +
    +
    +
    +

    Toasts

    + Documentation +
    + +
    + +
    + + Bootstrap + 11 mins ago + +
    +
    + Hello, world! This is a toast message. +
    +
    + `} /> + +
    +
    +
    +

    Tooltips

    + Documentation +
    + +
    + Tooltip on top + + + + + `} /> +
    +
    +
    +
    + + + + + + diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout-rtl/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout-rtl/index.astro new file mode 100644 index 000000000..1b0193573 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout-rtl/index.astro @@ -0,0 +1,231 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'مثال إتمام الشراء' +export const direction = 'rtl' +export const extra_css = ['../checkout/checkout.css'] +export const extra_js = [{ src: '../checkout/checkout.js' }] +export const body_class = 'bg-body-tertiary' +--- + +
    +
    +
    + +

    نموذج إتمام الشراء

    +

    فيما يلي مثال على نموذج تم إنشاؤه بالكامل باستخدام عناصر تحكم النموذج في Bootstrap. لكل مجموعة نماذج مطلوبة حالة تحقق يمكن تشغيلها بمحاولة إرسال النموذج دون استكماله.

    +
    + +
    +
    +

    + عربة التسوق + 3 +

    +
      +
    • +
      +
      اسم المنتج
      + وصف مختصر +
      + $12 +
    • +
    • +
      +
      المنتج الثاني
      + وصف مختصر +
      + $8 +
    • +
    • +
      +
      البند الثالث
      + وصف مختصر +
      + $5 +
    • +
    • +
      +
      رمز ترويجي
      + EXAMPLECODE +
      + -$5 +
    • +
    • + مجموع (USD) + $20 +
    • +
    + +
    +
    + + +
    +
    +
    +
    +

    عنوان الفوترة

    +
    +
    +
    + + +
    + يرجى إدخال اسم أول صحيح. +
    +
    + +
    + + +
    + يرجى إدخال اسم عائلة صحيح. +
    +
    + +
    + +
    + @ + +
    + اسم المستخدم الخاص بك مطلوب. +
    +
    +
    + +
    + + +
    + يرجى إدخال عنوان بريد إلكتروني صحيح لتصلكم تحديثات الشحن. +
    +
    + +
    + + +
    + يرجى إدخال عنوان الشحن الخاص بك. +
    +
    + +
    + + +
    + +
    + + +
    + يرجى اختيار بلد صحيح. +
    +
    + +
    + + +
    + يرجى اختيار اسم منطقة صحيح. +
    +
    + +
    + + +
    + الرمز البريدي مطلوب. +
    +
    +
    + +
    + +
    + + +
    + +
    + + +
    + +
    + +

    طريقة الدفع

    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + + الاسم الكامل كما هو معروض على البطاقة +
    + الاسم على البطاقة مطلوب +
    +
    + +
    + + +
    + رقم بطاقة الائتمان مطلوب +
    +
    + +
    + + +
    + تاريخ انتهاء الصلاحية مطلوب +
    +
    + +
    + + +
    + رمز الحماية مطلوب +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/checkout/checkout.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout/checkout.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/checkout/checkout.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/checkout/checkout.css diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/checkout/checkout.js b/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout/checkout.js similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/checkout/checkout.js rename to app/vendor/twbs/bootstrap/site/src/assets/examples/checkout/checkout.js diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout/index.astro new file mode 100644 index 000000000..029bc796b --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/checkout/index.astro @@ -0,0 +1,231 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Checkout example' +export const extra_css = ['checkout.css'] +export const extra_js = [{ src: 'checkout.js' }] +export const body_class = 'bg-body-tertiary' +--- + +
    +
    +
    + +

    Checkout form

    +

    Below is an example form built entirely with Bootstrap’s form controls. Each required form group has a validation state that can be triggered by attempting to submit the form without completing it.

    +
    + +
    +
    +

    + Your cart + 3 +

    +
      +
    • +
      +
      Product name
      + Brief description +
      + $12 +
    • +
    • +
      +
      Second product
      + Brief description +
      + $8 +
    • +
    • +
      +
      Third item
      + Brief description +
      + $5 +
    • +
    • +
      +
      Promo code
      + EXAMPLECODE +
      + −$5 +
    • +
    • + Total (USD) + $20 +
    • +
    + +
    +
    + + +
    +
    +
    +
    +

    Billing address

    +
    +
    +
    + + +
    + Valid first name is required. +
    +
    + +
    + + +
    + Valid last name is required. +
    +
    + +
    + +
    + @ + +
    + Your username is required. +
    +
    +
    + +
    + + +
    + Please enter a valid email address for shipping updates. +
    +
    + +
    + + +
    + Please enter your shipping address. +
    +
    + +
    + + +
    + +
    + + +
    + Please select a valid country. +
    +
    + +
    + + +
    + Please provide a valid state. +
    +
    + +
    + + +
    + Zip code required. +
    +
    +
    + +
    + +
    + + +
    + +
    + + +
    + +
    + +

    Payment

    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + + Full name as displayed on card +
    + Name on card is required +
    +
    + +
    + + +
    + Credit card number is required +
    +
    + +
    + + +
    + Expiration date required +
    +
    + +
    + + +
    + Security code required +
    +
    +
    + +
    + + +
    +
    +
    +
    + + +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cover/cover.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/cover/cover.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/cover/cover.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/cover/cover.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/cover/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/cover/index.astro new file mode 100644 index 000000000..3af731501 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/cover/index.astro @@ -0,0 +1,31 @@ +--- +export const title = 'Cover Template' +export const extra_css = ['cover.css'] +export const html_class = 'h-100' +export const body_class = 'd-flex h-100 text-center text-bg-dark' +--- + +
    +
    +
    +

    Cover

    + +
    +
    + +
    +

    Cover your page.

    +

    Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.

    +

    + Learn more +

    +
    + + +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard-rtl/dashboard.js b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard-rtl/dashboard.js similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard-rtl/dashboard.js rename to app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard-rtl/dashboard.js diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard-rtl/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard-rtl/index.astro new file mode 100644 index 000000000..c5758e95c --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard-rtl/index.astro @@ -0,0 +1,330 @@ +--- +export const title = 'قالب لوحة القيادة' +export const direction = 'rtl' +export const extra_css = ['../dashboard/dashboard.rtl.css'] +export const extra_js = [ + { src: 'https://cdn.jsdelivr.net/npm/chart.js@4.3.2/dist/chart.umd.js', integrity: 'sha384-eI7PSr3L1XLISH8JdDII5YN/njoSsxfbrkCTnJrzXt+ENP5MOVBxD+l6sEG4zoLp'}, + { src: 'dashboard.js'} +] +--- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +

    لوحة القيادة

    +
    +
    + + +
    + +
    +
    + + + +

    عنوان القسم

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #عنوانعنوانعنوانعنوان
    1,001بياناتعشوائيةتثريالجدول
    1,002تثريمبهةتصميمتنسيق
    1,003عشوائيةغنيةقيمةمفيدة
    1,003معلوماتتثريتوضيحيةعشوائية
    1,004الجدولبياناتتنسيققيمة
    1,005قيمةمبهةالجدولتثري
    1,006قيمةتوضيحيةغنيةعشوائية
    1,007تثريمفيدةمعلوماتمبهة
    1,008بياناتعشوائيةتثريالجدول
    1,009تثريمبهةتصميمتنسيق
    1,010عشوائيةغنيةقيمةمفيدة
    1,011معلوماتتثريتوضيحيةعشوائية
    1,012الجدولتثريتنسيققيمة
    1,013قيمةمبهةالجدولتصميم
    1,014قيمةتوضيحيةغنيةعشوائية
    1,015بياناتمفيدةمعلوماتالجدول
    +
    +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard/dashboard.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/dashboard.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard/dashboard.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/dashboard.css diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard/dashboard.js b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/dashboard.js similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard/dashboard.js rename to app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/dashboard.js diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard/dashboard.rtl.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/dashboard.rtl.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dashboard/dashboard.rtl.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/dashboard.rtl.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/index.astro new file mode 100644 index 000000000..4d33c7fb8 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/dashboard/index.astro @@ -0,0 +1,329 @@ +--- +export const title = 'Dashboard Template' +export const extra_css = ['dashboard.css'] +export const extra_js = [ + { src: 'https://cdn.jsdelivr.net/npm/chart.js@4.3.2/dist/chart.umd.js', integrity: 'sha384-eI7PSr3L1XLISH8JdDII5YN/njoSsxfbrkCTnJrzXt+ENP5MOVBxD+l6sEG4zoLp'}, + { src: 'dashboard.js'} +] +--- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    +
    +

    Dashboard

    +
    +
    + + +
    + +
    +
    + + + +

    Section title

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #HeaderHeaderHeaderHeader
    1,001randomdataplaceholdertext
    1,002placeholderirrelevantvisuallayout
    1,003datarichdashboardtabular
    1,003informationplaceholderillustrativedata
    1,004textrandomlayoutdashboard
    1,005dashboardirrelevanttextplaceholder
    1,006dashboardillustrativerichdata
    1,007placeholdertabularinformationirrelevant
    1,008randomdataplaceholdertext
    1,009placeholderirrelevantvisuallayout
    1,010datarichdashboardtabular
    1,011informationplaceholderillustrativedata
    1,012textplaceholderlayoutdashboard
    1,013dashboardirrelevanttextvisual
    1,014dashboardillustrativerichdata
    1,015randomtabularinformationtext
    +
    +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dropdowns/dropdowns.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/dropdowns/dropdowns.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/dropdowns/dropdowns.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/dropdowns/dropdowns.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/dropdowns/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/dropdowns/index.astro new file mode 100644 index 000000000..812109e41 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/dropdowns/index.astro @@ -0,0 +1,459 @@ +--- +export const title = 'Dropdowns' +export const extra_css = ['dropdowns.css'] +--- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + +
    + + + +
    + +
    + + diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/features.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/features/features.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/features.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/features/features.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/features/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/features/index.astro new file mode 100644 index 000000000..7a3a7640d --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/features/index.astro @@ -0,0 +1,337 @@ +--- +export const title = 'Features' +export const extra_css = ['features.css'] +--- + + + + Bootstrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Features examples

    + + + +
    + +
    +

    Hanging icons

    +
    +
    +
    + +
    +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading. We'll add onto it with another sentence and probably just keep going until we run out of words.

    + + Primary button + +
    +
    +
    +
    + +
    +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading. We'll add onto it with another sentence and probably just keep going until we run out of words.

    + + Primary button + +
    +
    +
    +
    + +
    +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading. We'll add onto it with another sentence and probably just keep going until we run out of words.

    + + Primary button + +
    +
    +
    +
    + +
    + +
    +

    Custom cards

    + +
    +
    +
    +
    +

    Short title, long jacket

    +
      +
    • + Bootstrap +
    • +
    • + + Earth +
    • +
    • + + 3d +
    • +
    +
    +
    +
    + +
    +
    +
    +

    Much longer title that wraps to multiple lines

    +
      +
    • + Bootstrap +
    • +
    • + + Pakistan +
    • +
    • + + 4d +
    • +
    +
    +
    +
    + +
    +
    +
    +

    Another longer title belongs here

    +
      +
    • + Bootstrap +
    • +
    • + + California +
    • +
    • + + 5d +
    • +
    +
    +
    +
    +
    +
    + +
    + +
    +

    Icon grid

    + +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    +
    + +
    + +
    +

    Features with title

    + +
    +
    +

    Left-aligned title explaining these awesome features

    +

    Paragraph of text beneath the heading to explain the heading. We'll add onto it with another sentence and probably just keep going until we run out of words.

    + Primary button +
    + +
    +
    +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    + +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    + +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    + +
    +
    + +
    +

    Featured title

    +

    Paragraph of text beneath the heading to explain the heading.

    +
    +
    +
    +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/unsplash-photo-1.jpg b/app/vendor/twbs/bootstrap/site/src/assets/examples/features/unsplash-photo-1.jpg similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/unsplash-photo-1.jpg rename to app/vendor/twbs/bootstrap/site/src/assets/examples/features/unsplash-photo-1.jpg diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/unsplash-photo-2.jpg b/app/vendor/twbs/bootstrap/site/src/assets/examples/features/unsplash-photo-2.jpg similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/unsplash-photo-2.jpg rename to app/vendor/twbs/bootstrap/site/src/assets/examples/features/unsplash-photo-2.jpg diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/unsplash-photo-3.jpg b/app/vendor/twbs/bootstrap/site/src/assets/examples/features/unsplash-photo-3.jpg similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/features/unsplash-photo-3.jpg rename to app/vendor/twbs/bootstrap/site/src/assets/examples/features/unsplash-photo-3.jpg diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/footers/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/footers/index.astro new file mode 100644 index 000000000..9aaaa9f68 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/footers/index.astro @@ -0,0 +1,179 @@ +--- +export const title = 'Footers' +--- + + + + Bootstrap + + + + + + + + + + +
    + +
    + +
    + +
    +
    +
    + + + + © {new Date().getFullYear()} Company, Inc +
    + + +
    +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + +
    + +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/grid/grid.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/grid/grid.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/grid/grid.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/grid/grid.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/grid/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/grid/index.astro new file mode 100644 index 000000000..2c01d8de9 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/grid/index.astro @@ -0,0 +1,185 @@ +--- +export const title = 'Grid Template' +export const extra_css = ['grid.css'] +export const body_class = 'py-4' +--- + +
    +
    + +

    Bootstrap grid examples

    +

    Basic grid layouts to get you familiar with building within the Bootstrap grid system.

    +

    In these examples the .themed-grid-col class is added to the columns to add some theming. This is not a class that is available in Bootstrap by default.

    + +

    Five grid tiers

    +

    There are five tiers to the Bootstrap grid system, one for each range of devices we support. Each tier starts at a minimum viewport size and automatically applies to the larger devices unless overridden.

    + +
    +
    .col-4
    +
    .col-4
    +
    .col-4
    +
    + +
    +
    .col-sm-4
    +
    .col-sm-4
    +
    .col-sm-4
    +
    + +
    +
    .col-md-4
    +
    .col-md-4
    +
    .col-md-4
    +
    + +
    +
    .col-lg-4
    +
    .col-lg-4
    +
    .col-lg-4
    +
    + +
    +
    .col-xl-4
    +
    .col-xl-4
    +
    .col-xl-4
    +
    + +
    +
    .col-xxl-4
    +
    .col-xxl-4
    +
    .col-xxl-4
    +
    + +

    Three equal columns

    +

    Get three equal-width columns starting at desktops and scaling to large desktops. On mobile devices, tablets and below, the columns will automatically stack.

    +
    +
    .col-md-4
    +
    .col-md-4
    +
    .col-md-4
    +
    + +

    Three equal columns alternative

    +

    By using the .row-cols-* classes, you can easily create a grid with equal columns.

    +
    +
    .col child of .row-cols-md-3
    +
    .col child of .row-cols-md-3
    +
    .col child of .row-cols-md-3
    +
    + +

    Three unequal columns

    +

    Get three columns starting at desktops and scaling to large desktops of various widths. Remember, grid columns should add up to twelve for a single horizontal block. More than that, and columns start stacking no matter the viewport.

    +
    +
    .col-md-3
    +
    .col-md-6
    +
    .col-md-3
    +
    + +

    Two columns

    +

    Get two columns starting at desktops and scaling to large desktops.

    +
    +
    .col-md-8
    +
    .col-md-4
    +
    + +

    Full width, single column

    +

    + No grid classes are necessary for full-width elements. +

    + +
    + +

    Two columns with two nested columns

    +

    Per the documentation, nesting is easy—just put a row of columns within an existing column. This gives you two columns starting at desktops and scaling to large desktops, with another two (equal widths) within the larger column.

    +

    At mobile device sizes, tablets and down, these columns and their nested columns will stack.

    +
    +
    +
    + .col-md-8 +
    +
    +
    .col-md-6
    +
    .col-md-6
    +
    +
    +
    .col-md-4
    +
    + +
    + +

    Mixed: mobile and desktop

    +

    The Bootstrap v5 grid system has six tiers of classes: xs (extra small, this class infix is not used), sm (small), md (medium), lg (large), xl (x-large), and xxl (xx-large). You can use nearly any combination of these classes to create more dynamic and flexible layouts.

    +

    Each tier of classes scales up, meaning if you plan on setting the same widths for md, lg, xl and xxl, you only need to specify md.

    +
    +
    .col-md-8
    +
    .col-6 .col-md-4
    +
    +
    +
    .col-6 .col-md-4
    +
    .col-6 .col-md-4
    +
    .col-6 .col-md-4
    +
    +
    +
    .col-6
    +
    .col-6
    +
    + +
    + +

    Mixed: mobile, tablet, and desktop

    +
    +
    .col-sm-6 .col-lg-8
    +
    .col-6 .col-lg-4
    +
    +
    +
    .col-6 .col-sm-4
    +
    .col-6 .col-sm-4
    +
    .col-6 .col-sm-4
    +
    + +
    + +

    Gutters

    +

    With .gx-* classes, the horizontal gutters can be adjusted.

    +
    +
    .col with .gx-4 gutters
    +
    .col with .gx-4 gutters
    +
    .col with .gx-4 gutters
    +
    .col with .gx-4 gutters
    +
    .col with .gx-4 gutters
    +
    .col with .gx-4 gutters
    +
    +

    Use the .gy-* classes to control the vertical gutters.

    +
    +
    .col with .gy-4 gutters
    +
    .col with .gy-4 gutters
    +
    .col with .gy-4 gutters
    +
    .col with .gy-4 gutters
    +
    .col with .gy-4 gutters
    +
    .col with .gy-4 gutters
    +
    +

    With .g-* classes, the gutters in both directions can be adjusted.

    +
    +
    .col with .g-3 gutters
    +
    .col with .g-3 gutters
    +
    .col with .g-3 gutters
    +
    .col with .g-3 gutters
    +
    .col with .g-3 gutters
    +
    .col with .g-3 gutters
    +
    +
    + +
    +
    + +

    Containers

    +

    Additional classes added in Bootstrap v4.4 allow containers that are 100% wide until a particular breakpoint. v5 adds a new xxl breakpoint.

    +
    + +
    .container
    +
    .container-sm
    +
    .container-md
    +
    .container-lg
    +
    .container-xl
    +
    .container-xxl
    +
    .container-fluid
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/headers/headers.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/headers/headers.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/headers/headers.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/headers/headers.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/headers/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/headers/index.astro new file mode 100644 index 000000000..a233ae903 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/headers/index.astro @@ -0,0 +1,294 @@ +--- +export const title = 'Headers' +export const extra_css = ['headers.css'] +--- + + + + Bootstrap + + + + + + + + + + + + + + + + + + + + + +
    +

    Headers examples

    + + + +
    + +
    +
    + +
    +
    + +
    + +
    +
    +
    + + + +
    + + + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + + + + + + + + +
    + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + + + + + + + + +
    +
    +
    + +
    + +
    +
    + + +
    + + + +
    +
    +
    + +
    +
    +
    +









    +
    +
    +









    +
    +
    +
    + +
    + + +
    + +
    + +
    + +
    + +
    +
    + + +
    + + +
    +
    +
    +
    + +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/bootstrap-docs.png b/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/bootstrap-docs.png new file mode 100644 index 000000000..a4e9b9864 Binary files /dev/null and b/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/bootstrap-docs.png differ diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/heroes/bootstrap-themes.png b/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/bootstrap-themes.png similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/heroes/bootstrap-themes.png rename to app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/bootstrap-themes.png diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/heroes/heroes.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/heroes.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/heroes/heroes.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/heroes.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/index.astro new file mode 100644 index 000000000..853776e7b --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/heroes/index.astro @@ -0,0 +1,124 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Heroes' +export const extra_css = ['heroes.css'] +--- + +
    +

    Heroes examples

    + +
    + +

    Centered hero

    +
    +

    Quickly design and customize responsive mobile-first sites with Bootstrap, the world’s most popular front-end open source toolkit, featuring Sass variables and mixins, responsive grid system, extensive prebuilt components, and powerful JavaScript plugins.

    +
    + + +
    +
    +
    + +
    + +
    +

    Centered screenshot

    +
    +

    Quickly design and customize responsive mobile-first sites with Bootstrap, the world’s most popular front-end open source toolkit, featuring Sass variables and mixins, responsive grid system, extensive prebuilt components, and powerful JavaScript plugins.

    +
    + + +
    +
    +
    +
    + Example image +
    +
    +
    + +
    + +
    +
    +
    + Bootstrap Themes +
    +
    +

    Responsive left-aligned hero with image

    +

    Quickly design and customize responsive mobile-first sites with Bootstrap, the world’s most popular front-end open source toolkit, featuring Sass variables and mixins, responsive grid system, extensive prebuilt components, and powerful JavaScript plugins.

    +
    + + +
    +
    +
    +
    + +
    + +
    +
    +
    +

    Vertically centered hero sign-up form

    +

    Below is an example form built entirely with Bootstrap’s form controls. Each required form group has a validation state that can be triggered by attempting to submit the form without completing it.

    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    + +
    + By clicking Sign up, you agree to the terms of use. +
    +
    +
    +
    + +
    + +
    +
    +
    +

    Border hero with cropped image and shadows

    +

    Quickly design and customize responsive mobile-first sites with Bootstrap, the world’s most popular front-end open source toolkit, featuring Sass variables and mixins, responsive grid system, extensive prebuilt components, and powerful JavaScript plugins.

    +
    + + +
    +
    +
    + +
    +
    +
    + +
    + +
    +
    +

    Dark color hero

    +
    +

    Quickly design and customize responsive mobile-first sites with Bootstrap, the world’s most popular front-end open source toolkit, featuring Sass variables and mixins, responsive grid system, extensive prebuilt components, and powerful JavaScript plugins.

    +
    + + +
    +
    +
    +
    + +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotron/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotron/index.astro new file mode 100644 index 000000000..6874af1ca --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotron/index.astro @@ -0,0 +1,43 @@ +--- +export const title = 'Jumbotron example' +--- + +
    +
    +
    + + Bootstrap + Jumbotron example + +
    + +
    +
    +

    Custom jumbotron

    +

    Using a series of utilities, you can create this jumbotron, just like the one in previous versions of Bootstrap. Check out the examples below for how you can remix and restyle it to your liking.

    + +
    +
    + +
    +
    +
    +

    Change the background

    +

    Swap the background-color utility and add a `.text-*` color utility to mix up the jumbotron look. Then, mix and match with additional component themes and more.

    + +
    +
    +
    +
    +

    Add borders

    +

    Or, keep it light and add a border for some added definition to the boundaries of your content. Be sure to look under the hood at the source HTML here as we've adjusted the alignment and sizing of both column's content for equal-height.

    + +
    +
    +
    + +
    + © {new Date().getFullYear()} +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotrons/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotrons/index.astro new file mode 100644 index 000000000..587e79302 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotrons/index.astro @@ -0,0 +1,79 @@ +--- +export const title = 'Jumbotrons' +export const extra_css = ['jumbotrons.css'] +--- + + + + Bootstrap + + + + + + + + + + + +
    +
    + +

    Jumbotron with icon

    +

    + This is a custom jumbotron featuring an SVG image at the top, some longer text that wraps early thanks to a responsive .col-* class, and a customized call to action. +

    +
    + + +
    +
    +
    + +
    + +
    +
    + + +

    Placeholder jumbotron

    +

    + This faded back jumbotron is useful for placeholder content. It's also a great way to add a bit of context to a page or section when no content is available and to encourage visitors to take a specific action. +

    + +
    +
    + +
    + +
    +
    +
    +

    Full-width jumbotron

    +

    + This takes the basic jumbotron above and makes its background edge-to-edge with a .container inside to align content. Similar to above, it's been recreated with built-in grid and utility classes. +

    +
    +
    +
    + +
    + +
    +
    +

    Basic jumbotron

    +

    + This is a simple Bootstrap jumbotron that sits within a .container, recreated with built-in utility classes. +

    +
    +
    + +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/jumbotrons/jumbotrons.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotrons/jumbotrons.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/jumbotrons/jumbotrons.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/jumbotrons/jumbotrons.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/list-groups/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/list-groups/index.astro new file mode 100644 index 000000000..220678f07 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/list-groups/index.astro @@ -0,0 +1,222 @@ +--- +export const title = 'List groups' +export const extra_css = ['list-groups.css'] +--- + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + + + +
    + +
    + + + +
    +
    + +
    + +
    +
    + + + + +
    +
    + +
    + +
    +
    + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/list-groups/list-groups.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/list-groups/list-groups.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/list-groups/list-groups.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/list-groups/list-groups.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/masonry/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/masonry/index.astro new file mode 100644 index 000000000..58aea3f14 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/masonry/index.astro @@ -0,0 +1,106 @@ +--- +export const title = 'Masonry example' +export const extra_js = [{ + src: 'https://cdn.jsdelivr.net/npm/masonry-layout@4.2.2/dist/masonry.pkgd.min.js', + integrity: 'sha384-GNFwBvfVxBkLMJpYMOABq3c+d3KnQxudP/mGPkzpZSTYykLBNsZEnG2D9G/X/+7D', + async: true +}] +import Placeholder from "@shortcodes/Placeholder.astro" +--- + +
    +

    Bootstrap and Masonry

    +

    Integrate Masonry with the Bootstrap grid system and cards component.

    + +

    Masonry is not included in Bootstrap. Add it by including the JavaScript plugin manually, or using a CDN like so:

    + +
    
    +<script src="https://cdn.jsdelivr.net/npm/masonry-layout@4.2.2/dist/masonry.pkgd.min.js" integrity="sha384-GNFwBvfVxBkLMJpYMOABq3c+d3KnQxudP/mGPkzpZSTYykLBNsZEnG2D9G/X/+7D" crossorigin="anonymous" async></script>
    +  
    + +

    By adding data-masonry='}"percentPosition": true }' to the .row wrapper, we can combine the powers of Bootstrap's responsive grid and Masonry's positioning.

    + +
    + +
    +
    +
    + +
    +
    Card title that wraps to a new line
    +

    This is a longer card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

    +
    +
    +
    +
    +
    +
    +
    +

    A well-known quote, contained in a blockquote element.

    +
    + +
    +
    +
    +
    +
    + +
    +
    Card title
    +

    This card has supporting text below as a natural lead-in to additional content.

    +

    Last updated 3 mins ago

    +
    +
    +
    +
    +
    +
    +
    +

    A well-known quote, contained in a blockquote element.

    +
    + +
    +
    +
    +
    +
    +
    +
    Card title
    +

    This card has a regular title and short paragraph of text below it.

    +

    Last updated 3 mins ago

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +

    A well-known quote, contained in a blockquote element.

    +
    + +
    +
    +
    +
    +
    +
    +
    Card title
    +

    This is another card with title and supporting text below. This card has some additional content to make it slightly taller overall.

    +

    Last updated 3 mins ago

    +
    +
    +
    +
    + +
    diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/modals/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/modals/index.astro new file mode 100644 index 000000000..9514f6f1f --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/modals/index.astro @@ -0,0 +1,147 @@ +--- +export const title = 'Modals' +export const extra_css = ['modals.css'] +--- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + + + +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/modals/modals.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/modals/modals.css similarity index 99% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/modals/modals.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/modals/modals.css index 924952ae3..194e16aca 100644 --- a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/modals/modals.css +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/modals/modals.css @@ -5,4 +5,3 @@ .modal-sheet .modal-footer { padding-bottom: 2rem; } - diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-bottom/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-bottom/index.astro new file mode 100644 index 000000000..35aa348c6 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-bottom/index.astro @@ -0,0 +1,42 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Bottom navbar example' +--- + +
    +
    +

    Bottom Navbar example

    +

    This example is a quick exercise to illustrate how the bottom navbar works.

    + View navbar docs » +
    +
    + diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-fixed/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-fixed/index.astro new file mode 100644 index 000000000..3524255c2 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-fixed/index.astro @@ -0,0 +1,40 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Fixed top navbar example' +export const extra_css = ['navbar-fixed.css'] +--- + + + +
    +
    +

    Navbar example

    +

    This example is a quick exercise to illustrate how fixed to top navbar works. As you scroll, it will remain fixed to the top of your browser’s viewport.

    + View navbar docs » +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbar-fixed/navbar-fixed.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-fixed/navbar-fixed.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbar-fixed/navbar-fixed.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-fixed/navbar-fixed.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-static/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-static/index.astro new file mode 100644 index 000000000..600b313ec --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-static/index.astro @@ -0,0 +1,40 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Top navbar example' +export const extra_css = ['navbar-static.css'] +--- + + + +
    +
    +

    Navbar example

    +

    This example is a quick exercise to illustrate how the top-aligned navbar works. As you scroll, this navbar remains in its original position and moves with the rest of the page.

    + View navbar docs » +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbar-static/navbar-static.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-static/navbar-static.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbar-static/navbar-static.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/navbar-static/navbar-static.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars-offcanvas/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars-offcanvas/index.astro new file mode 100644 index 000000000..ec6b03f76 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars-offcanvas/index.astro @@ -0,0 +1,147 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Navbar Template' +export const extra_css = ['navbars-offcanvas.css'] +--- + +
    + + + + + + +
    +
    +
    +

    Navbar with offcanvas examples

    +

    This example shows how responsive offcanvas menus work within the navbar. For positioning of navbars, checkout the top and fixed top examples.

    +

    From the top down, you'll see a dark navbar, light navbar and a responsive navbar—each with offcanvases built in. Resize your browser window to the large breakpoint to see the toggle for the offcanvas.

    +

    + Learn more about offcanvas navbars » +

    +
    +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbars-offcanvas/navbars-offcanvas.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars-offcanvas/navbars-offcanvas.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbars-offcanvas/navbars-offcanvas.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/navbars-offcanvas/navbars-offcanvas.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars/index.astro new file mode 100644 index 000000000..c48993f8d --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars/index.astro @@ -0,0 +1,450 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Navbar Template' +export const extra_css = ['navbars.css'] +--- + +
    + + + + + + + + + + + + + + + + + + +
    +

    Matching .container-xl...

    +
    + + + +
    + + + + + + +
    +
    +
    +

    Navbar examples

    +

    This example is a quick exercise to illustrate how the navbar and its contents work. Some navbars extend the width of the viewport, others are confined within a .container. For positioning of navbars, checkout the top and fixed top examples.

    +

    At the smallest breakpoint, the collapse plugin is used to hide the links and show a menu button to toggle the collapsed content.

    +

    + View navbar docs » +

    +
    +
    +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbars/navbars.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/navbars/navbars.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/navbars/navbars.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/navbars/navbars.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/offcanvas-navbar/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/offcanvas-navbar/index.astro new file mode 100644 index 000000000..ac94ca882 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/offcanvas-navbar/index.astro @@ -0,0 +1,140 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Offcanvas navbar template' +export const extra_css = ['offcanvas-navbar.css'] +export const extra_js = [{ src: 'offcanvas-navbar.js' }] +export const body_class = 'bg-body-tertiary' +export const aliases = '/docs/[[config:docs_version]]/examples/offcanvas/' +import Placeholder from "@shortcodes/Placeholder.astro" +--- + + + + + +
    +
    + +
    +

    Bootstrap

    + Since 2011 +
    +
    + +
    +
    Recent updates
    +
    + +

    + @username + Some representative placeholder content, with some information about this user. Imagine this being some sort of status update, perhaps? +

    +
    +
    + +

    + @username + Some more representative placeholder content, related to this other user. Another status update, perhaps. +

    +
    +
    + +

    + @username + This user also gets some representative placeholder content. Maybe they did something interesting, and you really want to highlight this in the recent updates. +

    +
    + + All updates + +
    + +
    +
    Suggestions
    +
    + +
    +
    + Full Name + Follow +
    + @username +
    +
    +
    + +
    +
    + Full Name + Follow +
    + @username +
    +
    +
    + +
    +
    + Full Name + Follow +
    + @username +
    +
    + + All suggestions + +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/offcanvas-navbar/offcanvas-navbar.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/offcanvas-navbar/offcanvas-navbar.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/offcanvas-navbar/offcanvas-navbar.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/offcanvas-navbar/offcanvas-navbar.css diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/offcanvas-navbar/offcanvas-navbar.js b/app/vendor/twbs/bootstrap/site/src/assets/examples/offcanvas-navbar/offcanvas-navbar.js similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/offcanvas-navbar/offcanvas-navbar.js rename to app/vendor/twbs/bootstrap/site/src/assets/examples/offcanvas-navbar/offcanvas-navbar.js diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/pricing/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/pricing/index.astro new file mode 100644 index 000000000..e51668fce --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/pricing/index.astro @@ -0,0 +1,186 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Pricing example' +export const extra_css = ['pricing.css'] +--- + + + + Check + + + + +
    +
    + + +
    +

    Pricing

    +

    Quickly build an effective pricing table for your potential customers with this Bootstrap example. It’s built with default Bootstrap components and utilities with little customization.

    +
    +
    + +
    +
    +
    +
    +
    +

    Free

    +
    +
    +

    $0/mo

    +
      +
    • 10 users included
    • +
    • 2 GB of storage
    • +
    • Email support
    • +
    • Help center access
    • +
    + +
    +
    +
    +
    +
    +
    +

    Pro

    +
    +
    +

    $15/mo

    +
      +
    • 20 users included
    • +
    • 10 GB of storage
    • +
    • Priority email support
    • +
    • Help center access
    • +
    + +
    +
    +
    +
    +
    +
    +

    Enterprise

    +
    +
    +

    $29/mo

    +
      +
    • 30 users included
    • +
    • 15 GB of storage
    • +
    • Phone and email support
    • +
    • Help center access
    • +
    + +
    +
    +
    +
    + +

    Compare plans

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FreeProEnterprise
    Public
    Private
    Permissions
    Sharing
    Unlimited members
    Extra security
    +
    +
    + + +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/pricing/pricing.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/pricing/pricing.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/pricing/pricing.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/pricing/pricing.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/product/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/product/index.astro new file mode 100644 index 000000000..7c98d11a1 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/product/index.astro @@ -0,0 +1,187 @@ +--- +export const title = 'Product example' +export const extra_css = ['product.css'] +--- + + + + + + + + + + + + + + + + +
    +
    +
    +

    Designed for engineers

    +

    Build anything you want with Aperture

    + +
    +
    +
    +
    + +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    + +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    + +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    + +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    +
    +

    Another headline

    +

    And an even wittier subheading.

    +
    +
    +
    +
    +
    + + diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/product/product.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/product/product.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/product/product.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/product/product.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/sidebars/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/sidebars/index.astro new file mode 100644 index 000000000..de67a80b6 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/sidebars/index.astro @@ -0,0 +1,352 @@ +--- +export const title = 'Sidebars' +export const extra_css = ['sidebars.css'] +export const extra_js = [{src: 'sidebars.js'}] +--- + + + + Bootstrap + + + + + + + + + + + + + + + + + + + + + +
    +

    Sidebars examples

    + + + +
    + + + +
    + +
    + + + Icon-only + + + +
    + +
    + +
    + + + Collapsible + + +
    + +
    + + + +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sidebars/sidebars.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/sidebars/sidebars.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sidebars/sidebars.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/sidebars/sidebars.css diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sidebars/sidebars.js b/app/vendor/twbs/bootstrap/site/src/assets/examples/sidebars/sidebars.js similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sidebars/sidebars.js rename to app/vendor/twbs/bootstrap/site/src/assets/examples/sidebars/sidebars.js diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/sign-in/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/sign-in/index.astro new file mode 100644 index 000000000..ffbd75b99 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/sign-in/index.astro @@ -0,0 +1,32 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Signin Template' +export const extra_css = ['sign-in.css'] +export const body_class = 'd-flex align-items-center py-4 bg-body-tertiary' +--- + +
    +
    + +

    Please sign in

    + +
    + + +
    +
    + + +
    + +
    + + +
    + +

    © 2017–{new Date().getFullYear()}

    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sign-in/sign-in.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/sign-in/sign-in.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sign-in/sign-in.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/sign-in/sign-in.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/starter-template/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/starter-template/index.astro new file mode 100644 index 000000000..0af316538 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/starter-template/index.astro @@ -0,0 +1,108 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Starter Template' +--- + + + + + + + Bootstrap + + + + +
    +
    + + + Starter template + +
    + +
    +

    Get started with Bootstrap

    +

    Quickly and easily get started with Bootstrap's compiled, production-ready files with this barebones example featuring some basic HTML and helpful links. Download all our examples to get started.

    + + + +
    + +
    +
    +

    Starter projects

    +

    Ready to go beyond the starter template? Check out these open source projects that you can quickly duplicate to a new GitHub repository.

    + +
    + +
    +

    Guides

    +

    Read more detailed instructions and documentation on using or contributing to Bootstrap.

    + +
    +
    +
    +
    + Created by the Bootstrap team · © {new Date().getFullYear()} +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer-navbar/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer-navbar/index.astro new file mode 100644 index 000000000..9b9b5ebb9 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer-navbar/index.astro @@ -0,0 +1,52 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Sticky Footer Navbar Template' +export const extra_css = ['sticky-footer-navbar.css'] +export const html_class = 'h-100' +export const body_class = 'd-flex flex-column h-100' +--- + +
    + + +
    + + +
    +
    +

    Sticky footer with fixed navbar

    +

    Pin a footer to the bottom of the viewport in desktop browsers with this custom HTML and CSS. A fixed navbar has been added with padding-top: 60px; on the main > .container.

    +

    Back to the default sticky footer minus the navbar.

    +
    +
    + +
    +
    + Place sticky footer content here. +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sticky-footer-navbar/sticky-footer-navbar.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer-navbar/sticky-footer-navbar.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sticky-footer-navbar/sticky-footer-navbar.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer-navbar/sticky-footer-navbar.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer/index.astro b/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer/index.astro new file mode 100644 index 000000000..b436ad0c4 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer/index.astro @@ -0,0 +1,23 @@ +--- +import { getVersionedDocsPath } from '@libs/path' + +export const title = 'Sticky Footer Template' +export const extra_css = ['sticky-footer.css'] +export const html_class = 'h-100' +export const body_class = 'd-flex flex-column h-100' +--- + + +
    +
    +

    Sticky footer

    +

    Pin a footer to the bottom of the viewport in desktop browsers with this custom HTML and CSS.

    +

    Use the sticky footer with a fixed navbar if need be, too.

    +
    +
    + +
    +
    + Place sticky footer content here. +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sticky-footer/sticky-footer.css b/app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer/sticky-footer.css similarity index 100% rename from app/vendor/twbs/bootstrap/site/content/docs/5.3/examples/sticky-footer/sticky-footer.css rename to app/vendor/twbs/bootstrap/site/src/assets/examples/sticky-footer/sticky-footer.css diff --git a/app/vendor/twbs/bootstrap/site/src/assets/partials/sidebar.js b/app/vendor/twbs/bootstrap/site/src/assets/partials/sidebar.js new file mode 100644 index 000000000..bf42e7b5e --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/partials/sidebar.js @@ -0,0 +1,30 @@ +// NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT +// IT'S ALL JUST JUNK FOR OUR DOCS! +// ++++++++++++++++++++++++++++++++++++++++++ + +/* + * JavaScript for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + * For details, see https://creativecommons.org/licenses/by/3.0/. + */ + +export default () => { + // Scroll the active sidebar link into view + const sidenav = document.querySelector('.bd-sidebar') + const sidenavActiveLink = document.querySelector('.bd-links-nav .active') + + if (!sidenav || !sidenavActiveLink) { + return + } + + const sidenavHeight = sidenav.clientHeight + const sidenavActiveLinkTop = sidenavActiveLink.offsetTop + const sidenavActiveLinkHeight = sidenavActiveLink.clientHeight + const viewportTop = sidenavActiveLinkTop + const viewportBottom = viewportTop - sidenavHeight + sidenavActiveLinkHeight + + if (sidenav.scrollTop > viewportTop || sidenav.scrollTop < viewportBottom) { + sidenav.scrollTop = viewportTop - (sidenavHeight / 2) + (sidenavActiveLinkHeight / 2) + } +} diff --git a/app/vendor/twbs/bootstrap/site/src/assets/partials/snippets.js b/app/vendor/twbs/bootstrap/site/src/assets/partials/snippets.js new file mode 100644 index 000000000..498071b41 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/partials/snippets.js @@ -0,0 +1,168 @@ +// NOTICE!!! Initially embedded in our docs this JavaScript +// file contains elements that can help you create reproducible +// use cases in StackBlitz for instance. +// In a real project please adapt this content to your needs. +// ++++++++++++++++++++++++++++++++++++++++++ + +/* + * JavaScript for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + * For details, see https://creativecommons.org/licenses/by/3.0/. + */ + +/* global bootstrap: false */ + +export default () => { + // -------- + // Tooltips + // -------- + // Instantiate all tooltips in a docs or StackBlitz + document.querySelectorAll('[data-bs-toggle="tooltip"]') + .forEach(tooltip => { + new bootstrap.Tooltip(tooltip) + }) + + // -------- + // Popovers + // -------- + // Instantiate all popovers in docs or StackBlitz + document.querySelectorAll('[data-bs-toggle="popover"]') + .forEach(popover => { + new bootstrap.Popover(popover) + }) + + // ------------------------------- + // Toasts + // ------------------------------- + // Used by 'Placement' example in docs or StackBlitz + const toastPlacement = document.getElementById('toastPlacement') + if (toastPlacement) { + document.getElementById('selectToastPlacement').addEventListener('change', function () { + if (!toastPlacement.dataset.originalClass) { + toastPlacement.dataset.originalClass = toastPlacement.className + } + + toastPlacement.className = `${toastPlacement.dataset.originalClass} ${this.value}` + }) + } + + // Instantiate all toasts in docs pages only + document.querySelectorAll('.bd-example .toast') + .forEach(toastNode => { + const toast = new bootstrap.Toast(toastNode, { + autohide: false + }) + + toast.show() + }) + + // Instantiate all toasts in docs pages only + // js-docs-start live-toast + const toastTrigger = document.getElementById('liveToastBtn') + const toastLiveExample = document.getElementById('liveToast') + + if (toastTrigger) { + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample) + toastTrigger.addEventListener('click', () => { + toastBootstrap.show() + }) + } + // js-docs-end live-toast + + // ------------------------------- + // Alerts + // ------------------------------- + // Used in 'Show live alert' example in docs or StackBlitz + + // js-docs-start live-alert + const alertPlaceholder = document.getElementById('liveAlertPlaceholder') + const appendAlert = (message, type) => { + const wrapper = document.createElement('div') + wrapper.innerHTML = [ + `' + ].join('') + + alertPlaceholder.append(wrapper) + } + + const alertTrigger = document.getElementById('liveAlertBtn') + if (alertTrigger) { + alertTrigger.addEventListener('click', () => { + appendAlert('Nice, you triggered this alert message!', 'success') + }) + } + // js-docs-end live-alert + + // -------- + // Carousels + // -------- + // Instantiate all non-autoplaying carousels in docs or StackBlitz + document.querySelectorAll('.carousel:not([data-bs-ride="carousel"])') + .forEach(carousel => { + bootstrap.Carousel.getOrCreateInstance(carousel) + }) + + // ------------------------------- + // Checks & Radios + // ------------------------------- + // Indeterminate checkbox example in docs and StackBlitz + document.querySelectorAll('.bd-example-indeterminate [type="checkbox"]') + .forEach(checkbox => { + if (checkbox.id.includes('Indeterminate')) { + checkbox.indeterminate = true + } + }) + + // ------------------------------- + // Links + // ------------------------------- + // Disable empty links in docs examples only + document.querySelectorAll('.bd-content [href="#"]') + .forEach(link => { + link.addEventListener('click', event => { + event.preventDefault() + }) + }) + + // ------------------------------- + // Modal + // ------------------------------- + // Modal 'Varying modal content' example in docs and StackBlitz + // js-docs-start varying-modal-content + const exampleModal = document.getElementById('exampleModal') + if (exampleModal) { + exampleModal.addEventListener('show.bs.modal', event => { + // Button that triggered the modal + const button = event.relatedTarget + // Extract info from data-bs-* attributes + const recipient = button.getAttribute('data-bs-whatever') + // If necessary, you could initiate an Ajax request here + // and then do the updating in a callback. + + // Update the modal's content. + const modalTitle = exampleModal.querySelector('.modal-title') + const modalBodyInput = exampleModal.querySelector('.modal-body input') + + modalTitle.textContent = `New message to ${recipient}` + modalBodyInput.value = recipient + }) + } + // js-docs-end varying-modal-content + + // ------------------------------- + // Offcanvas + // ------------------------------- + // 'Offcanvas components' example in docs only + const myOffcanvas = document.querySelectorAll('.bd-example-offcanvas .offcanvas') + if (myOffcanvas) { + myOffcanvas.forEach(offcanvas => { + offcanvas.addEventListener('show.bs.offcanvas', event => { + event.preventDefault() + }, false) + }) + } +} diff --git a/app/vendor/twbs/bootstrap/site/src/assets/search.js b/app/vendor/twbs/bootstrap/site/src/assets/search.js new file mode 100644 index 000000000..1077babdb --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/search.js @@ -0,0 +1,59 @@ +// NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT +// IT'S ALL JUST JUNK FOR OUR DOCS! +// ++++++++++++++++++++++++++++++++++++++++++ + +/*! + * JavaScript for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2024-2025 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + * For details, see https://creativecommons.org/licenses/by/3.0/. + */ + +import docsearch from '@docsearch/js' + +(() => { + // These values will be replaced by Astro's Vite plugin + const CONFIG = { + apiKey: '__API_KEY__', + indexName: '__INDEX_NAME__', + appId: '__APP_ID__' + } + + const searchElement = document.getElementById('docsearch') + + if (!searchElement) { + return + } + + const siteDocsVersion = searchElement.getAttribute('data-bd-docs-version') + + docsearch({ + apiKey: CONFIG.apiKey, + indexName: CONFIG.indexName, + appId: CONFIG.appId, + container: searchElement, + searchParameters: { + facetFilters: [`version:${siteDocsVersion}`] + }, + transformItems(items) { + return items.map(item => { + const liveUrl = 'https://getbootstrap.com/' + + item.url = window.location.origin.startsWith(liveUrl) ? + // On production, return the result as is + item.url : + // On development or Netlify, replace `item.url` with a trailing slash, + // so that the result link is relative to the server root + item.url.replace(liveUrl, '/') + + // Prevent jumping to first header + if (item.anchor === 'content') { + item.url = item.url.replace(/#content$/, '') + item.anchor = null + } + + return item + }) + } + }) +})() diff --git a/app/vendor/twbs/bootstrap/site/src/assets/snippets.js b/app/vendor/twbs/bootstrap/site/src/assets/snippets.js new file mode 100644 index 000000000..d18ab41c4 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/snippets.js @@ -0,0 +1,15 @@ +/* + * JavaScript for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + * For details, see https://creativecommons.org/licenses/by/3.0/. + */ + +// Note that this file is not published; we only include it in scripts.html +// for StackBlitz to work + +/* eslint-disable import/no-unresolved */ +import snippets from 'js/partials/snippets.js' +/* eslint-enable import/no-unresolved */ + +snippets() diff --git a/app/vendor/twbs/bootstrap/site/src/assets/stackblitz.js b/app/vendor/twbs/bootstrap/site/src/assets/stackblitz.js new file mode 100644 index 000000000..0b450a7d4 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/assets/stackblitz.js @@ -0,0 +1,89 @@ +// NOTICE!!! Initially embedded in our docs this JavaScript +// file contains elements that can help you create reproducible +// use cases in StackBlitz for instance. +// In a real project please adapt this content to your needs. +// ++++++++++++++++++++++++++++++++++++++++++ + +/*! + * JavaScript for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2024-2025 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + * For details, see https://creativecommons.org/licenses/by/3.0/. + */ + +import sdk from '@stackblitz/sdk' +// eslint-disable-next-line import/no-unresolved +import snippetsContent from './partials/snippets.js?raw' + +// These values will be replaced by Astro's Vite plugin +const CONFIG = { + cssCdn: '__CSS_CDN__', + jsBundleCdn: '__JS_BUNDLE_CDN__', + docsVersion: '__DOCS_VERSION__' +} + +// Open in StackBlitz logic +document.querySelectorAll('.btn-edit').forEach(btn => { + btn.addEventListener('click', event => { + const codeSnippet = event.target.closest('.bd-code-snippet') + const exampleEl = codeSnippet.querySelector('.bd-example') + + const htmlSnippet = exampleEl.innerHTML + const jsSnippet = codeSnippet.querySelector('.btn-edit').getAttribute('data-sb-js-snippet') + // Get extra classes for this example + const classes = Array.from(exampleEl.classList).join(' ') + + openBootstrapSnippet(htmlSnippet, jsSnippet, classes) + }) +}) + +const openBootstrapSnippet = (htmlSnippet, jsSnippet, classes) => { + const indexHtml = ` + + + + + + + Bootstrap Example + + + + +${htmlSnippet.trimStart().replace(/^/gm, ' ').replace(/^ {4}$/gm, '').trimEnd()} + + +` + + // Modify the snippets content to convert export default to a variable and invoke it + let modifiedSnippetsContent = '' + + if (jsSnippet) { + // Replace export default with a variable assignment + modifiedSnippetsContent = snippetsContent.replace( + 'export default () => {', + 'const snippets_default = () => {' + ) + + // Add IIFE wrapper and execution + modifiedSnippetsContent = `(() => { + ${modifiedSnippetsContent} + + // + snippets_default(); +})();` + } + + const project = { + files: { + 'index.html': indexHtml, + ...(jsSnippet && { 'index.js': modifiedSnippetsContent }) + }, + title: 'Bootstrap Example', + description: `Official example from ${window.location.href}`, + template: jsSnippet ? 'javascript' : 'html', + tags: ['bootstrap'] + } + + sdk.openProject(project, { openFile: 'index.html' }) +} diff --git a/app/vendor/twbs/bootstrap/site/src/components/Ads.astro b/app/vendor/twbs/bootstrap/site/src/components/Ads.astro new file mode 100644 index 000000000..2a53c0a61 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/Ads.astro @@ -0,0 +1,9 @@ +--- +--- + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/DocsSidebar.astro b/app/vendor/twbs/bootstrap/site/src/components/DocsSidebar.astro new file mode 100644 index 000000000..1282ed702 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/DocsSidebar.astro @@ -0,0 +1,84 @@ +--- +import { getData } from '@libs/data' +import { getConfig } from '@libs/config' +import { docsPages } from '@libs/content' +import { getSlug } from '@libs/utils' + +const sidebar = getData('sidebar') +--- + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/Scripts.astro b/app/vendor/twbs/bootstrap/site/src/components/Scripts.astro new file mode 100644 index 000000000..b17057d20 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/Scripts.astro @@ -0,0 +1,17 @@ +--- +import { getVersionedBsJsProps } from '@libs/bootstrap' +import type { Layout } from '@libs/layout' + +interface Props { + layout: Layout +} + +const { layout } = Astro.props +--- + + + + + + +{layout === 'docs' && diff --git a/app/vendor/twbs/bootstrap/site/src/components/head/Favicons.astro b/app/vendor/twbs/bootstrap/site/src/components/head/Favicons.astro new file mode 100644 index 000000000..9c462c90b --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/head/Favicons.astro @@ -0,0 +1,11 @@ +--- +import { getVersionedDocsPath } from '@libs/path' +--- + + + + + + + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/head/Head.astro b/app/vendor/twbs/bootstrap/site/src/components/head/Head.astro new file mode 100644 index 000000000..434ba8359 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/head/Head.astro @@ -0,0 +1,54 @@ +--- +import { getConfig } from '@libs/config' +import { getVersionedDocsPath } from '@libs/path' +import type { Layout } from '@libs/layout' +import Stylesheet from '@components/head/Stylesheet.astro' +import Favicons from '@components/head/Favicons.astro' +import Social from '@components/head/Social.astro' +import Analytics from '@components/head/Analytics.astro' +import Scss from '@components/head/Scss.astro' + +interface Props { + description: string + direction?: 'rtl' + layout: Layout + robots: string | undefined + thumbnail: string + title: string +} + +const { description, direction, layout, robots, thumbnail, title } = Astro.props + +const canonicalUrl = new URL(Astro.url.pathname, Astro.site) + +const isHome = Astro.url.pathname === '/' +const pageTitle = isHome + ? `${getConfig().title} · ${getConfig().subtitle}` + : `${title} · ${getConfig().title} v${getConfig().docs_version}` +--- + + + + + + + + + + + + + + + +{pageTitle} + +{robots && } + + + + + + + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/head/Scss.astro b/app/vendor/twbs/bootstrap/site/src/components/head/Scss.astro new file mode 100644 index 000000000..fc10fe75a --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/head/Scss.astro @@ -0,0 +1,7 @@ +--- +--- + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/head/Social.astro b/app/vendor/twbs/bootstrap/site/src/components/head/Social.astro new file mode 100644 index 000000000..bf97d1e8b --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/head/Social.astro @@ -0,0 +1,31 @@ +--- +import { getConfig } from '@libs/config' +import { getVersionedDocsPath } from '@libs/path' +import { getStaticImageSize } from '@libs/image' +import type { Layout } from '@libs/layout' + +interface Props { + description: string + layout: Layout + thumbnail: string + title: string +} + +const { description, layout, thumbnail, title } = Astro.props + +const socialImageUrl = new URL(getVersionedDocsPath(`assets/${thumbnail}`), Astro.site) +const socialImageSize = await getStaticImageSize(`/docs/[version]/assets/${thumbnail}`) +--- + + + + + + + + + + + + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/head/Stylesheet.astro b/app/vendor/twbs/bootstrap/site/src/components/head/Stylesheet.astro new file mode 100644 index 000000000..d0203893a --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/head/Stylesheet.astro @@ -0,0 +1,13 @@ +--- +import { getVersionedBsCssProps } from '@libs/bootstrap' +import type { Layout } from '@libs/layout' + +interface Props { + direction?: 'rtl' + layout: Layout +} + +const { direction } = Astro.props +--- + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/header/Header.astro b/app/vendor/twbs/bootstrap/site/src/components/header/Header.astro new file mode 100644 index 000000000..e68b160a1 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/header/Header.astro @@ -0,0 +1,20 @@ +--- +import type { CollectionEntry } from 'astro:content' +import type { Layout } from '@libs/layout' +import Skippy from '@components/header/Skippy.astro' +import Symbols from '@components/icons/Symbols.astro' +import Navigation from '@components/header/Navigation.astro' + +interface Props { + addedIn?: CollectionEntry<'docs'>['data']['added'] + layout: Layout + title: string +} + +const { addedIn, layout, title } = Astro.props +--- + + + + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/header/LinkItem.astro b/app/vendor/twbs/bootstrap/site/src/components/header/LinkItem.astro new file mode 100644 index 000000000..0b3f42f50 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/header/LinkItem.astro @@ -0,0 +1,24 @@ +--- +interface Props { + active?: boolean + class?: string + href: string + rel?: HTMLAnchorElement['rel'] + target?: HTMLAnchorElement['target'] + track?: boolean +} + +const { active, class: className, track, ...props } = Astro.props + +const content = await Astro.slots.render('default') +--- + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/header/Navigation.astro b/app/vendor/twbs/bootstrap/site/src/components/header/Navigation.astro new file mode 100644 index 000000000..4e55d54ff --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/header/Navigation.astro @@ -0,0 +1,131 @@ +--- +import type { CollectionEntry } from 'astro:content' +import { getConfig } from '@libs/config' +import { getVersionedDocsPath } from '@libs/path' +import type { Layout } from '@libs/layout' +import BootstrapWhiteFillIcon from '@components/icons/BootstrapWhiteFillIcon.astro' +import GitHubIcon from '@components/icons/GitHubIcon.astro' +import HamburgerIcon from '@components/icons/HamburgerIcon.astro' +import LinkItem from '@components/header/LinkItem.astro' +import OpenCollectiveIcon from '@components/icons/OpenCollectiveIcon.astro' +import XIcon from '@components/icons/XIcon.astro' +import Versions from '@components/header/Versions.astro' +import ThemeToggler from '@layouts/partials/ThemeToggler.astro' + +interface Props { + addedIn?: CollectionEntry<'docs'>['data']['added'] + layout: Layout + title: string +} + +const { addedIn, layout, title } = Astro.props +--- + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/header/Skippy.astro b/app/vendor/twbs/bootstrap/site/src/components/header/Skippy.astro new file mode 100644 index 000000000..aa5ba1dbd --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/header/Skippy.astro @@ -0,0 +1,22 @@ +--- +import type { Layout } from '@libs/layout' + +interface Props { + layout: Layout +} + +const { layout } = Astro.props +--- + +
    +
    + Skip to main content + { + layout === 'docs' && ( + + Skip to docs navigation + + ) + } +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/header/Versions.astro b/app/vendor/twbs/bootstrap/site/src/components/header/Versions.astro new file mode 100644 index 000000000..a1119e0a3 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/header/Versions.astro @@ -0,0 +1,96 @@ +--- +import type { CollectionEntry } from 'astro:content' +import { getConfig } from '@libs/config' +import type { Layout } from '@libs/layout' +import { getVersionedDocsPath } from '@libs/path' + +interface Props { + addedIn?: CollectionEntry<'docs'>['data']['added'] + layout: Layout +} + +const { addedIn, layout } = Astro.props +const { slug, version } = Astro.params + +const isHome = Astro.url.pathname === '/' + +let versionsLink = '' + +if (layout === 'docs' && version === getConfig().docs_version) { + versionsLink = `${slug}/` +} else if (layout === 'single' && Astro.url.pathname.startsWith(getVersionedDocsPath(''))) { + versionsLink = Astro.url.pathname.replace(getVersionedDocsPath(''), '') +} + +const addedIn51 = addedIn?.version === '5.1' +const addedIn52 = addedIn?.version === '5.2' +const addedIn53 = addedIn?.version === '5.3' +--- + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/CSSVariables.astro b/app/vendor/twbs/bootstrap/site/src/components/home/CSSVariables.astro new file mode 100644 index 000000000..92dad9dd2 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/CSSVariables.astro @@ -0,0 +1,71 @@ +--- +import { getVersionedDocsPath } from '@libs/path' +import Code from '@shortcodes/Code.astro' +--- + +
    +
    +
    + +
    +

    Build and extend in real-time with CSS variables

    +

    + Bootstrap 5 is evolving with each release to better utilize CSS variables for global theme styles, individual + components, and even utilities. We provide dozens of variables for colors, font styles, and more at a :root level for use anywhere. On components and utilities, CSS variables are scoped to the relevant class and can easily + be modified. +

    +

    + + Learn more about CSS variables + + +

    +
    +
    +
    +

    Using CSS variables

    +

    + Use any of our global :root variables to write new styles. CSS variables use the var(--bs-variableName) syntax and can be inherited by children + elements. +

    + +
    +
    +

    Customizing via CSS variables

    +

    + Override global, component, or utility class variables to customize Bootstrap just how you like. No need to + redeclare each rule, just a new variable value. +

    + +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/ComponentUtilities.astro b/app/vendor/twbs/bootstrap/site/src/components/home/ComponentUtilities.astro new file mode 100644 index 000000000..b54d4e408 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/ComponentUtilities.astro @@ -0,0 +1,158 @@ +--- +import { getVersionedDocsPath } from '@libs/path' +import Code from '@shortcodes/Code.astro' +--- + +
    +
    +
    + +
    + +
    + +
    +

    Components, meet the Utility API

    +

    + New in Bootstrap 5, our utilities are now generated by our Utility API. We built it as a feature-packed Sass map that can be quickly and easily customized. It's never been easier to + add, remove, or modify any utility classes. Make utilities responsive, add pseudo-class variants, and give them + custom names. +

    +
    +
    +
    +

    Quickly customize components

    +

    + Apply any of our included utility classes to our components to customize their appearance, like the navigation + example below. There are hundreds of classes available—from positioning and sizing to colors and effects. Mix them with CSS variable overrides for + even more control. +

    +
    + + +
    + + + + +`} + lang="html" + /> +

    + + Explore customized components + + +

    +
    +
    +

    Create and extend utilities

    +

    + Use Bootstrap's utility API to modify any of our included utilities or create your own custom utilities for any + project. Import Bootstrap first, then use Sass map functions to modify, add, or remove utilities. +

    + +

    + + Explore the utility API + + +

    +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/Customize.astro b/app/vendor/twbs/bootstrap/site/src/components/home/Customize.astro new file mode 100644 index 000000000..7422c517c --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/Customize.astro @@ -0,0 +1,69 @@ +--- +import { getVersionedDocsPath } from '@libs/path' +import Code from '@shortcodes/Code.astro' +--- + +
    +
    + +
    +

    Customize everything with Sass

    +

    + Bootstrap utilizes Sass for a modular and customizable architecture. Import only the components you need, enable + global options like gradients and shadows, and write your own CSS with our variables, maps, functions, and mixins. +

    +

    + + Learn more about customizing + + +

    +
    + +
    +
    +

    Include all of Bootstrap’s Sass

    +

    Import one stylesheet and you're off to the races with every feature of our CSS.

    + +

    Learn more about our global Sass options.

    +
    +
    +

    Include what you need

    +

    The easiest way to customize Bootstrap—include only the CSS you need.

    + +

    Learn more about using Bootstrap with Sass.

    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/GetStarted.astro b/app/vendor/twbs/bootstrap/site/src/components/home/GetStarted.astro new file mode 100644 index 000000000..4ad6807c7 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/GetStarted.astro @@ -0,0 +1,115 @@ +--- +import { getConfig } from '@libs/config' +import { getVersionedDocsPath } from '@libs/path' +import Code from '@shortcodes/Code.astro' +--- + +
    +
    + +
    +

    Get started any way you want

    +

    + Jump right into building with Bootstrap—use the CDN, install it via package manager, or download the source code. +

    +

    + + Read installation docs + + +

    +
    + +
    +
    + +

    Install via package manager

    +

    + Install Bootstrap’s source Sass and JavaScript files via npm, RubyGems, Composer, or Meteor. Package-managed + installs don’t include documentation or our full build scripts. You can also use any demo from our Examples repo to quickly jumpstart Bootstrap projects. +

    + + +

    + Read our installation docs for more info and additional + package managers. +

    +
    +
    + +

    Include via CDN

    +

    + When you only need to include Bootstrap’s compiled CSS or JS, you can use jsDelivr. See it in action with our simple quick start, or browse the examples to jumpstart your next project. You can also + choose to include Popper and our JS separately. +

    + `} + lang="html" + /> + `} + lang="html" + /> +
    + +
    +

    Read our getting started guides

    +

    Get a jump on including Bootstrap's source files in a new project with our official guides.

    + +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/Icons.astro b/app/vendor/twbs/bootstrap/site/src/components/home/Icons.astro new file mode 100644 index 000000000..4991dab59 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/Icons.astro @@ -0,0 +1,28 @@ +--- +import { getConfig } from '@libs/config' +import CircleSquareIcon from '@components/icons/CircleSquareIcon.astro' +import ResponsiveImage from '@layouts/partials/ResponsiveImage.astro' +--- + +
    +
    +
    + +
    +

    Personalize it with Bootstrap Icons

    +

    + Bootstrap Icons is an open source SVG icon library featuring over 1,800 glyphs, with + more added every release. They're designed to work in any project, whether you use Bootstrap itself or not. Use them + as SVGs or icon fonts—both options give you vector scaling and easy customization via CSS. +

    +

    + + Get Bootstrap Icons + + +

    +
    +
    + +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/MastHead.astro b/app/vendor/twbs/bootstrap/site/src/components/home/MastHead.astro new file mode 100644 index 000000000..f9054bac3 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/MastHead.astro @@ -0,0 +1,60 @@ +--- +import { getConfig } from '@libs/config' +import { getVersionedDocsPath } from '@libs/path' +import Ads from '@components/Ads.astro' +import Code from '@components/shortcodes/Code.astro' +import ResponsiveImage from '@layouts/partials/ResponsiveImage.astro' +--- + +
    +
    +
    + + + Get Security Updates for Bootstrap 3 & 4 + + + + +

    Build fast, responsive sites with Bootstrap

    +

    + Powerful, extensible, and feature-packed frontend toolkit. Build and customize with Sass, utilize prebuilt grid + system and components, and bring projects to life with powerful JavaScript plugins. +

    + +

    + Currently v{getConfig().current_version} + · + Download + · + All releases +

    + +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/Plugins.astro b/app/vendor/twbs/bootstrap/site/src/components/home/Plugins.astro new file mode 100644 index 000000000..236ac5a15 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/Plugins.astro @@ -0,0 +1,90 @@ +--- +import { getVersionedDocsPath } from '@libs/path' +import { getData } from '@libs/data' +import Code from '@shortcodes/Code.astro' + +const plugins = getData('plugins') +--- + +
    +
    +
    + +
    +

    Powerful JavaScript plugins without jQuery

    +

    + Add toggleable hidden elements, modals and offcanvas menus, popovers and tooltips, and so much more—all without + jQuery. Bootstrap's JavaScript is HTML-first, meaning most plugins are added with data attributes in your + HTML. Need more control? Include individual plugins programmatically. +

    +

    + + Learn more about Bootstrap JavaScript + + +

    +
    +
    +
    +

    Data attribute API

    +

    + Why write more JavaScript when you can write HTML? Nearly all of Bootstrap's JavaScript plugins feature a + first-class data API, allowing you to use JavaScript just by adding data attributes. +

    +
    + +
    + + + +
    `} + lang="html" + /> +

    + Learn more about our JavaScript as modules and using the programmatic API. +

    +
    +
    +

    Comprehensive set of plugins

    +

    + Bootstrap features a dozen plugins that you can drop into any project. Drop them in all at once, or choose just + the ones you need. +

    +
    +
    + { + plugins.map((plugin) => { + return ( + + ) + }) + } +
    +
    + +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/home/Themes.astro b/app/vendor/twbs/bootstrap/site/src/components/home/Themes.astro new file mode 100644 index 000000000..68dd5e12b --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/home/Themes.astro @@ -0,0 +1,35 @@ +--- +import { getConfig } from '@libs/config' +import DropletFillIcon from '@components/icons/DropletFillIcon.astro' +import ResponsiveImage from '@layouts/partials/ResponsiveImage.astro' +--- + +
    +
    +
    + +
    +

    Make it yours with official Bootstrap Themes

    +

    + Take Bootstrap to the next level with premium themes from the official Bootstrap Themes marketplace. Themes are built on Bootstrap as their own extended frameworks, rich with new components and plugins, + documentation, and powerful build tools. +

    +

    + + Browse Bootstrap Themes + + +

    +
    +
    + +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/AddedIn.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/AddedIn.astro new file mode 100644 index 000000000..d9a26ce50 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/AddedIn.astro @@ -0,0 +1,16 @@ +--- +/* + * Outputs badge to identify the first version something was added + */ + +interface Props { + version: string +} + +const { version } = Astro.props +--- + +Added in v{version} diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/BsTable.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/BsTable.astro new file mode 100644 index 000000000..df80455ff --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/BsTable.astro @@ -0,0 +1,16 @@ +--- +interface Props { + /** + * The CSS class to apply to the table. + * Note that the prop is not used in this component, but in a rehype plugin applying the classes to the table element + * directly on the HTML AST (HAST) generated by Astro. + * @default "table" + * @see src/libs/rehype.ts + */ + class?: string +} +--- + +
    + +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Callout.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Callout.astro new file mode 100644 index 000000000..11243c848 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Callout.astro @@ -0,0 +1,44 @@ +--- +import { getCalloutByName } from '@libs/content' +import type { MarkdownInstance } from 'astro' + +interface Props { + /** + * The name of an existing callout to display located in `src/content/callouts`. + * This will override any content passed in via the default slot. + */ + name?: + | 'danger-async-methods' + | 'info-mediaqueries-breakpoints' + | 'info-npm-starter' + | 'info-prefersreducedmotion' + | 'info-sanitizer' + | 'warning-color-assistive-technologies' + | 'warning-data-bs-title-vs-title' + | 'warning-input-support' + /** + * The type of callout to display. One of `info`, `danger`, or `warning`. + * @default 'info' + */ + type?: 'danger' | 'info' | 'warning' +} + +const { name, type = 'info' } = Astro.props + +let Content: MarkdownInstance<{}>['Content'] | undefined + +if (name) { + const callout = await getCalloutByName(name) + + if (!callout) { + throw new Error(`Could not find callout with name '${name}'.`) + } + + const namedCallout = await callout.render() + Content = namedCallout.Content +} +--- + +
    + {Content ? : } +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/CalloutDeprecatedDarkVariants.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/CalloutDeprecatedDarkVariants.astro new file mode 100644 index 000000000..4033900d9 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/CalloutDeprecatedDarkVariants.astro @@ -0,0 +1,19 @@ +--- +/* + * Outputs message about dark mode component variants being deprecated in v5.3. + */ + +interface Props { + component: string +} + +const { component } = Astro.props +--- + +
    +

    + Heads up! Dark variants for components were deprecated in v5.3.0 with the introduction of color modes. + Instead of adding .{component}-dark, set data-bs-theme="dark" on the root element, a parent + wrapper, or the component itself. +

    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Code.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Code.astro new file mode 100644 index 000000000..231002a50 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Code.astro @@ -0,0 +1,156 @@ +--- +import fs from 'node:fs' +import path from 'node:path' +import { Prism } from '@astrojs/prism' + +interface Props { + /** + * The CSS class(es) to be added to the `pre` HTML element when rendering code blocks in Markdown. + * Note that this prop is not used when the component is invoked directly. + */ + class?: string + /** + * The code to highlight. + * If an array is passed, elements will be joined with a new line. + */ + code?: string | string[] + /** + * The CSS class(es) to be added to the `div` wrapper HTML element. + */ + containerClass?: string + /** + * The language to use for highlighting. + * @see https://prismjs.com/#supported-languages + */ + lang?: string + /** + * If the `filePath` prop is defined, this prop can be used to specify a regex containing a match group to extract + * only a part of the file. + */ + fileMatch?: string + /** + * A path to the file containing the code to highlight relative to the root of the repository. + * This takes precedence over the `code` prop. + */ + filePath?: string +} + +const { class: className, code, containerClass, fileMatch, filePath, lang } = Astro.props + +let codeToDisplay = filePath + ? fs.readFileSync(path.join(process.cwd(), filePath), 'utf8') + : Array.isArray(code) + ? code.join('\n') + : code + +if (filePath && fileMatch && codeToDisplay) { + const match = codeToDisplay.match(new RegExp(fileMatch)) + + if (!match || !match[0]) { + throw new Error(`The file at ${filePath} does not contains a match for the regex '${fileMatch}'.`) + } + + codeToDisplay = match[0] +} +--- + + + +
    + { + Astro.slots.has('pre') ? ( + + ) : ( +
    + +
    + ) + } +
    + { + codeToDisplay && lang ? ( + + ) : ( + /* prettier-ignore */
    + ) + } +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/DeprecatedIn.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/DeprecatedIn.astro new file mode 100644 index 000000000..50ba42b95 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/DeprecatedIn.astro @@ -0,0 +1,17 @@ +--- +/* + * Outputs badge to identify the version something was deprecated + */ + +interface Props { + version: string +} + +const { version } = Astro.props +--- + + + Deprecated in v{version} + diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Example.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Example.astro new file mode 100644 index 000000000..a09fffeb3 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Example.astro @@ -0,0 +1,105 @@ +--- +import { replacePlaceholdersInHtml } from '@libs/placeholder' +import { Prism } from '@astrojs/prism' + +interface Props { + /** + * Defines if extra JS snippet should be added to StackBlitz or not. + * @default false + */ + addStackblitzJs?: boolean + /** + * The example code. + * If an array is passed, elements will be joined with a new line. + */ + code: string | string[] + /** + * The CSS class(es) to be added to the preview wrapping `div` element. + */ + class?: string + /** + * The preview wrapping `div` element ID. + */ + id?: string + /** + * Language used to display the code. + * @default 'html' + */ + lang?: string + /** + * Defines if the markup should be visible or not. + * @default true + */ + showMarkup?: boolean + /** + * Defines if the preview should be visible or not. + * @default true + */ + showPreview?: boolean +} + +const { + addStackblitzJs = false, + code, + class: className, + id, + lang = 'html', + showMarkup = true, + showPreview = true +} = Astro.props + +let markup = Array.isArray(code) ? code.join('\n') : code +markup = replacePlaceholdersInHtml(markup) + +const simplifiedMarkup = markup + .replace( + //g, + (match, classes) => `...` + ) + .replace( + //g, + (match, classes) => `...` + ) +--- + +
    + { + showPreview && ( +
    + +
    + ) + } + + { + showMarkup && ( + <> + {showPreview && ( +
    + {lang} +
    + + +
    +
    + )} +
    + +
    + + ) + } +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/GuideFooter.mdx b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/GuideFooter.mdx new file mode 100644 index 000000000..426a71f27 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/GuideFooter.mdx @@ -0,0 +1,3 @@ +
    + +_See something wrong or out of date here? Please [open an issue on GitHub]([[config:repo]]/issues/new/choose). Need help troubleshooting? [Search or start a discussion]([[config:repo]]/discussions) on GitHub._ diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDataAttributes.mdx b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDataAttributes.mdx new file mode 100644 index 000000000..b7c6c0a7a --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDataAttributes.mdx @@ -0,0 +1,5 @@ +As options can be passed via data attributes or JavaScript, you can append an option name to `data-bs-`, as in `data-bs-animation="{value}"`. Make sure to change the case type of the option name from “_camelCase_” to “_kebab-case_” when passing the options via data attributes. For example, use `data-bs-custom-class="beautifier"` instead of `data-bs-customClass="beautifier"`. + +As of Bootstrap 5.2.0, all components support an **experimental** reserved data attribute `data-bs-config` that can house simple component configuration as a JSON string. When an element has `data-bs-config='{"delay":0, "title":123}'` and `data-bs-title="456"` attributes, the final `title` value will be `456` and the separate data attributes will override values given on `data-bs-config`. In addition, existing data attributes are able to house JSON values like `data-bs-delay='{"show":0,"hide":150}'`. + +The final configuration object is the merged result of `data-bs-config`, `data-bs-`, and `js object` where the latest given key-value overrides the others. diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDismiss.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDismiss.astro new file mode 100644 index 000000000..d1da8fc4d --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDismiss.astro @@ -0,0 +1,29 @@ +--- +import Code from '@shortcodes/Code.astro' + +interface Props { + name: string +} + +const { name } = Astro.props +--- + +

    + Dismissal can be achieved with the data-bs-dismiss attribute on a button within the {name} as demonstrated below: +

    + +`} + lang="html" +/> + +

    + or on a button outside the {name} using the additional data-bs-target as demonstrated below: +

    + +`} + lang="html" +/> diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDocs.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDocs.astro new file mode 100644 index 000000000..cf756af8c --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/JsDocs.astro @@ -0,0 +1,69 @@ +--- +import fs from 'node:fs' +import { getConfig } from '@libs/config' +import Code from '@shortcodes/Code.astro' + +// Prints everything between `// js-docs-start "name"` and `// js-docs-end "name"` +// comments in the docs. + +interface Props { + /** + * Reference name used to find the content to display within the content of the `file` prop. + */ + name: string + /** + * File path that contains the content to display relative to the root of the repository. + */ + file: string +} + +const { name, file } = Astro.props + +if (!name || !file) { + throw new Error( + `Missing required parameter(s) for the '' component, expected both 'name' and 'file' but got 'name: ${name}' and 'file: ${file}'.` + ) +} + +let content: string + +try { + const fileContent = fs.readFileSync(file, 'utf8') + + const matches = fileContent.match(new RegExp(`\/\/ js-docs-start ${name}\n((?:.|\n)*)\/\/ js-docs-end ${name}`, 'm')) + + if (!matches || !matches[1]) { + throw new Error( + `Failed to find the content named '${name}', make sure that '// js-docs-start ${name}' and '// js-docs-end ${name}' are defined.` + ) + } + + content = matches[1] + + // Fix the identation by removing extra spaces at the beginning of each line + const lines = content.split('\n') + const spaceCounts = lines.filter((line) => line.trim().length > 0).map((line) => line.match(/^ */)[0].length) + const minSpaces = spaceCounts.length ? Math.min(...spaceCounts) : 0 + content = lines.map((line) => line.slice(minSpaces)).join('\n') +} catch (error) { + throw new Error(`Failed to find the content to render in the '' component at '${file}'.`, { + cause: error + }) +} +--- + + +
    + + {file} + +
    + +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Placeholder.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Placeholder.astro new file mode 100644 index 000000000..3ebde32bc --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Placeholder.astro @@ -0,0 +1,27 @@ +--- +import { getPlaceholder, type PlaceholderOptions } from '@libs/placeholder' + +type Props = Partial + +const { + options: { background, color, showText, showTitle, text, title }, + props, + type +} = getPlaceholder(Astro.props) +--- + +{ + type === 'img' ? ( + + ) : ( + + {showTitle && {title}} + + {showText && ( + + {text} + + )} + + ) +} diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/ScssDocs.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/ScssDocs.astro new file mode 100644 index 000000000..6c267570e --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/ScssDocs.astro @@ -0,0 +1,71 @@ +--- +import fs from 'node:fs' +import { getConfig } from '@libs/config' +import Code from '@shortcodes/Code.astro' + +// Prints everything between `// scss-docs-start "name"` and `// scss-docs-end "name"` +// comments in the docs. + +interface Props { + /** + * Reference name used to find the content to display within the content of the `file` prop. + */ + name: string + /** + * File path that contains the content to display relative to the root of the repository. + */ + file: string +} + +const { name, file } = Astro.props + +if (!name || !file) { + throw new Error( + `Missing required parameter(s) for the '' component, expected both 'name' and 'file' but got 'name: ${name}' and 'file: ${file}'.` + ) +} + +let content: string + +try { + const fileContent = fs.readFileSync(file, 'utf8') + + const matches = fileContent.match( + new RegExp(`\/\/ scss-docs-start ${name}\n((?:.|\n)*)\/\/ scss-docs-end ${name}`, 'm') + ) + + if (!matches || !matches[1]) { + throw new Error( + `Failed to find the content named '${name}', make sure that '// scss-docs-start ${name}' and '// scss-docs-end ${name}' are defined.` + ) + } + + content = matches[1].replaceAll(' !default', '') + + // Fix the identation by removing extra spaces at the beginning of each line + const lines = content.split('\n') + const spaceCounts = lines.filter((line) => line.trim().length > 0).map((line) => line.match(/^ */)[0].length) + const minSpaces = spaceCounts.length ? Math.min(...spaceCounts) : 0 + content = lines.map((line) => line.slice(minSpaces)).join('\n') +} catch (error) { + throw new Error(`Failed to find the content to render in the '' component at '${file}'.`, { + cause: error + }) +} +--- + + +
    + + {file} + +
    + +
    +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Table.astro b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Table.astro new file mode 100644 index 000000000..853b19701 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/Table.astro @@ -0,0 +1,31 @@ +--- +import Code from '@shortcodes/Code.astro' +import * as tableContent from '@shortcodes/TableContent.md' + +interface Props { + /** + * Any class(es) to be added to the `` element (both in the example and code snippet). + */ + class?: string + /** + * Show a simplified version in the example code snippet by replacing the table content inside `
    ` & `
    ` + * with `...`. + * @default true + */ + simplified?: boolean +} + +const { class: className, simplified = true } = Astro.props + +const tableCode = ` +${simplified ? ' ...' : await tableContent.compiledContent()} +` +--- + +
    + + +
    +
    + + diff --git a/app/vendor/twbs/bootstrap/site/src/components/shortcodes/TableContent.md b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/TableContent.md new file mode 100644 index 000000000..cee54c6d3 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/components/shortcodes/TableContent.md @@ -0,0 +1,28 @@ + + + # + First + Last + Handle + + + + + 1 + Mark + Otto + @mdo + + + 2 + Jacob + Thornton + @fat + + + 3 + John + Doe + @social + + diff --git a/app/vendor/twbs/bootstrap/site/src/content/callouts/danger-async-methods.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/danger-async-methods.md new file mode 100644 index 000000000..7b7a654b7 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/callouts/danger-async-methods.md @@ -0,0 +1 @@ +**All API methods are asynchronous and start a transition.** They return to the caller as soon as the transition is started, but before it ends. In addition, a method call on a transitioning component will be ignored. [Learn more in our JavaScript docs.](/docs/[[config:docs_version]]/getting-started/javascript/#asynchronous-functions-and-transitions) diff --git a/app/vendor/twbs/bootstrap/site/src/content/callouts/info-mediaqueries-breakpoints.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/info-mediaqueries-breakpoints.md new file mode 100644 index 000000000..52be67386 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/callouts/info-mediaqueries-breakpoints.md @@ -0,0 +1 @@ +**Why subtract .02px?** Browsers don’t currently support [range context queries](https://www.w3.org/TR/mediaqueries-4/#range-context), so we work around the limitations of [`min-` and `max-` prefixes](https://www.w3.org/TR/mediaqueries-4/#mq-min-max) and viewports with fractional widths (which can occur under certain conditions on high-dpi devices, for instance) by using values with higher precision. diff --git a/app/vendor/twbs/bootstrap/site/layouts/partials/callouts/info-npm-starter.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/info-npm-starter.md similarity index 100% rename from app/vendor/twbs/bootstrap/site/layouts/partials/callouts/info-npm-starter.md rename to app/vendor/twbs/bootstrap/site/src/content/callouts/info-npm-starter.md diff --git a/app/vendor/twbs/bootstrap/site/src/content/callouts/info-prefersreducedmotion.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/info-prefersreducedmotion.md new file mode 100644 index 000000000..49d81ef8b --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/callouts/info-prefersreducedmotion.md @@ -0,0 +1 @@ +The animation effect of this component is dependent on the `prefers-reduced-motion` media query. See the [reduced motion section of our accessibility documentation](/docs/[[config:docs_version]]/getting-started/accessibility/#reduced-motion). diff --git a/app/vendor/twbs/bootstrap/site/src/content/callouts/info-sanitizer.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/info-sanitizer.md new file mode 100644 index 000000000..516975b32 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/callouts/info-sanitizer.md @@ -0,0 +1 @@ +By default, this component uses the built-in content sanitizer, which strips out any HTML elements that are not explicitly allowed. See the [sanitizer section in our JavaScript documentation](/docs/[[config:docs_version]]/getting-started/javascript/#sanitizer) for more details. diff --git a/app/vendor/twbs/bootstrap/site/src/content/callouts/warning-color-assistive-technologies.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/warning-color-assistive-technologies.md new file mode 100644 index 000000000..8afa62ee8 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/callouts/warning-color-assistive-technologies.md @@ -0,0 +1 @@ +**Accessibility tip:** Using color to add meaning only provides a visual indication, which will not be conveyed to users of assistive technologies like screen readers. Please ensure the meaning is obvious from the content itself (e.g., the visible text with a [_sufficient_ color contrast](/docs/[[config:docs_version]]/getting-started/accessibility/#color-contrast)) or is included through alternative means, such as additional text hidden with the `.visually-hidden` class. diff --git a/app/vendor/twbs/bootstrap/site/layouts/partials/callouts/warning-data-bs-title-vs-title.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/warning-data-bs-title-vs-title.md similarity index 100% rename from app/vendor/twbs/bootstrap/site/layouts/partials/callouts/warning-data-bs-title-vs-title.md rename to app/vendor/twbs/bootstrap/site/src/content/callouts/warning-data-bs-title-vs-title.md diff --git a/app/vendor/twbs/bootstrap/site/layouts/partials/callouts/warning-input-support.md b/app/vendor/twbs/bootstrap/site/src/content/callouts/warning-input-support.md similarity index 100% rename from app/vendor/twbs/bootstrap/site/layouts/partials/callouts/warning-input-support.md rename to app/vendor/twbs/bootstrap/site/src/content/callouts/warning-input-support.md diff --git a/app/vendor/twbs/bootstrap/site/src/content/config.ts b/app/vendor/twbs/bootstrap/site/src/content/config.ts new file mode 100644 index 000000000..387a0052e --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/config.ts @@ -0,0 +1,45 @@ +import { z, defineCollection } from 'astro:content' + +const docsSchema = z.object({ + added: z + .object({ + show_badge: z.boolean().optional(), + version: z.string() + }) + .optional(), + aliases: z.string().or(z.string().array()).optional(), + description: z.string(), + direction: z.literal('rtl').optional(), + extra_js: z + .object({ + async: z.boolean().optional(), + src: z.string() + }) + .array() + .optional(), + sections: z + .object({ + description: z.string(), + title: z.string() + }) + .array() + .optional(), + thumbnail: z.string().optional(), + title: z.string(), + toc: z.boolean().optional() +}) + +const docsCollection = defineCollection({ + schema: docsSchema +}) + +const calloutsSchema = z.object({}) + +const calloutsCollection = defineCollection({ + schema: calloutsSchema +}) + +export const collections = { + docs: docsCollection, + callouts: calloutsCollection +} diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/about/brand.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/about/brand.mdx new file mode 100644 index 000000000..0b1716221 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/about/brand.mdx @@ -0,0 +1,41 @@ +--- +title: Brand guidelines +description: Documentation and examples for Bootstrap’s logo and brand usage guidelines. +toc: true +--- + +Have a need for Bootstrap’s brand resources? Great! We have only a few guidelines we follow, and in turn ask you to follow as well. + +## Logo + +When referencing Bootstrap, use our logo mark. Do not modify our logos in any way. Do not use Bootstrap’s branding for your own open or closed source projects. + +
    + Bootstrap +
    + +Our logo mark is also available in black and white. All rules for our primary logo apply to these as well. + +
    +
    + Bootstrap +
    +
    + Bootstrap +
    +
    + +## Name + +Bootstrap should always be referred to as just **Bootstrap**. No capital _s_. + +
    +
    +
    Bootstrap
    + Correct +
    +
    +
    BootStrap
    + Incorrect +
    +
    diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/about/license.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/about/license.mdx new file mode 100644 index 000000000..6479df67c --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/about/license.mdx @@ -0,0 +1,32 @@ +--- +title: License FAQs +description: Commonly asked questions about Bootstrap’s open source license. +--- + +Bootstrap is released under the MIT license and is copyright {new Date().getFullYear()}. Boiled down to smaller chunks, it can be described with the following conditions. + +## It requires you to: + +- Keep the license and copyright notice included in Bootstrap’s CSS and JavaScript files when you use them in your works + +## It permits you to: + +- Freely download and use Bootstrap, in whole or in part, for personal, private, company internal, or commercial purposes +- Use Bootstrap in packages or distributions that you create +- Modify the source code +- Grant a sublicense to modify and distribute Bootstrap to third parties not included in the license + +## It forbids you to: + +- Hold the authors and license owners liable for damages as Bootstrap is provided without warranty +- Hold the creators or copyright holders of Bootstrap liable +- Redistribute any piece of Bootstrap without proper attribution +- Use any marks owned by Bootstrap in any way that might state or imply that Bootstrap endorses your distribution +- Use any marks owned by Bootstrap in any way that might state or imply that you created the Bootstrap software in question + +## It does not require you to: + +- Include the source of Bootstrap itself, or of any modifications you may have made to it, in any redistribution you may assemble that includes it +- Submit changes that you make to Bootstrap back to the Bootstrap project (though such feedback is encouraged) + +The full Bootstrap license is located [in the project repository]([[config:repo]]/blob/v[[config:current_version]]/LICENSE) for more information. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/about/overview.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/about/overview.mdx new file mode 100644 index 000000000..efd16c543 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/about/overview.mdx @@ -0,0 +1,27 @@ +--- +title: About Bootstrap +description: Learn more about the team maintaining Bootstrap, how and why the project started, and how to get involved. +aliases: + - "/about/" + - "/docs/[[config:docs_version]]/about/" +--- + +## Team + +Bootstrap is maintained by a [small team of developers](https://github.com/orgs/twbs/people) on GitHub. We’re actively looking to grow this team and would love to hear from you if you’re excited about CSS at scale, writing and maintaining vanilla JavaScript plugins, and improving build tooling processes for frontend code. + +## History + +Originally created by a designer and a developer at Twitter, Bootstrap has become one of the most popular front-end frameworks and open source projects in the world. + +Bootstrap was created at Twitter in mid-2010 by [@mdo](https://x.com/mdo) and [@fat](https://x.com/fat). Prior to being an open-sourced framework, Bootstrap was known as _Twitter Blueprint_. A few months into development, Twitter held its [first Hack Week](https://blog.x.com/engineering/en_us/a/2010/hack-week) and the project exploded as developers of all skill levels jumped in without any external guidance. It served as the style guide for internal tools development at the company for over a year before its public release, and continues to do so today. + +Originally [released](https://blog.x.com/developer/en_us/a/2011/bootstrap-twitter) on , we’ve since had over [twenty releases]([[config:repo]]/releases), including two major rewrites with v2 and v3. With Bootstrap 2, we added responsive functionality to the entire framework as an optional stylesheet. Building on that with Bootstrap 3, we rewrote the library once more to make it responsive by default with a mobile first approach. + +With Bootstrap 4, we once again rewrote the project to account for two key architectural changes: a migration to Sass and the move to CSS’s flexbox. Our intention is to help in a small way to move the web development community forward by pushing for newer CSS properties, fewer dependencies, and new technologies across more modern browsers. + +Our latest release, Bootstrap 5, focuses on improving v4’s codebase with as few major breaking changes as possible. We improved existing features and components, removed support for older browsers, dropped jQuery for regular JavaScript, and embraced more future-friendly technologies like CSS custom properties as part of our tooling. + +## Get involved + +Get involved with Bootstrap development by [opening an issue]([[config:repo]]/issues/new/choose) or submitting a pull request. Read our [contributing guidelines]([[config:repo]]/blob/v[[config:current_version]]/.github/CONTRIBUTING.md) for information on how we develop. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/about/team.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/about/team.mdx new file mode 100644 index 000000000..46b03d877 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/about/team.mdx @@ -0,0 +1,23 @@ +--- +title: Team +description: An overview of the founding team and core contributors to Bootstrap. +--- + +import { getData } from '@libs/data' + +Bootstrap is maintained by the founding team and a small group of invaluable core contributors, with the massive support and involvement of our community. + +
    + {getData('core-team').map((member) => { + return ( + + {`@${member.user}`} + + {member.name} @{member.user} + + + ) + })} +
    + +Get involved with Bootstrap development by [opening an issue]([[config:repo]]/issues/new/choose) or submitting a pull request. Read our [contributing guidelines]([[config:repo]]/blob/v[[config:current_version]]/.github/CONTRIBUTING.md) for information on how we develop. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/about/translations.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/about/translations.mdx new file mode 100644 index 000000000..7db4ab846 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/about/translations.mdx @@ -0,0 +1,20 @@ +--- +title: Translations +description: Links to community-translated Bootstrap documentation sites. +--- + +import { getData } from '@libs/data' + +Community members have translated Bootstrap’s documentation into various languages. None are officially supported and they may not always be up-to-date. + + + +**We don’t help organize or host translations, we just link to them.** + +Finished a new or better translation? Open a pull request to add it to our list. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/components/accordion.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/components/accordion.mdx new file mode 100644 index 000000000..06c95d4a2 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/components/accordion.mdx @@ -0,0 +1,240 @@ +--- +title: Accordion +description: Build vertically collapsing accordions in combination with our Collapse JavaScript plugin. +aliases: + - "/components/" + - "/docs/[[config:docs_version]]/components/" +toc: true +--- + +## How it works + +The accordion uses [collapse]([[docsref:/components/collapse]]) internally to make it collapsible. + + + +## Example + +Click the accordions below to expand/collapse the accordion content. + +To render an accordion that’s expanded by default: +- add the `.show` class on the `.accordion-collapse` element. +- drop the `.collapsed` class from the `.accordion-button` element and set its `aria-expanded` attribute to `true`. + + +
    +

    + +

    +
    +
    + This is the first item’s accordion body. It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    +
    +

    + +

    +
    +
    + This is the second item’s accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    +
    +

    + +

    +
    +
    + This is the third item’s accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    + `} /> + +### Flush + +Add `.accordion-flush` to remove some borders and rounded corners to render accordions edge-to-edge with their parent container. + + +
    +

    + +

    +
    +
    Placeholder content for this accordion, which is intended to demonstrate the .accordion-flush class. This is the first item’s accordion body.
    +
    +
    +
    +

    + +

    +
    +
    Placeholder content for this accordion, which is intended to demonstrate the .accordion-flush class. This is the second item’s accordion body. Let’s imagine this being filled with some actual content.
    +
    +
    +
    +

    + +

    +
    +
    Placeholder content for this accordion, which is intended to demonstrate the .accordion-flush class. This is the third item’s accordion body. Nothing more exciting happening here in terms of content, but just filling up the space to make it look, at least at first glance, a bit more representative of how this would look in a real-world application.
    +
    +
    + `} /> + +### Always open + +Omit the `data-bs-parent` attribute on each `.accordion-collapse` to make accordion items stay open when another item is opened. + + +
    +

    + +

    +
    +
    + This is the first item’s accordion body. It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    +
    +

    + +

    +
    +
    + This is the second item’s accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    +
    +

    + +

    +
    +
    + This is the third item’s accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
    +
    +
    + `} /> + +## Accessibility + +Please read the [collapse accessibility section]([[docsref:/components/collapse#accessibility]]) for more information. + +## CSS + +### Variables + + + +As part of Bootstrap’s evolving CSS variables approach, accordions now use local CSS variables on `.accordion` for enhanced real-time customization. Values for the CSS variables are set via Sass, so Sass customization is still supported, too. + + + +### Sass variables + + + +## Usage + +The collapse plugin utilizes a few classes to handle the heavy lifting: + +- `.collapse` hides the content +- `.collapse.show` shows the content +- `.collapsing` is added when the transition starts, and removed when it finishes + +These classes can be found in `_transitions.scss`. + +### Via data attributes + +Just add `data-bs-toggle="collapse"` and a `data-bs-target` to the element to automatically assign control of one or more collapsible elements. The `data-bs-target` attribute accepts a CSS selector to apply the collapse to. Be sure to add the class `collapse` to the collapsible element. If you’d like it to default open, add the additional class `show`. + +To add accordion group management to a collapsible area, add the data attribute `data-bs-parent="#selector"`. + +### Via JavaScript + +Enable manually with: + +```js +const accordionCollapseElementList = document.querySelectorAll('#myAccordion.collapse') +const accordionCollapseList = [...accordionCollapseElementList].map(accordionCollapseEl => new bootstrap.Collapse(accordionCollapseEl)) +``` + +### Options + + + + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +`parent` | selector, DOM element | `null` | If parent is provided, then all collapsible elements under the specified parent will be closed when this collapsible item is shown. (similar to traditional accordion behavior - this is dependent on the `card` class). The attribute has to be set on the target collapsible area. | +`toggle` | boolean | `true` | Toggles the collapsible element on invocation. | + + +### Methods + + + +Activates your content as a collapsible element. Accepts an optional options `object`. + +You can create a collapse instance with the constructor, for example: + +```js +const bsCollapse = new bootstrap.Collapse('#myCollapse', { + toggle: false +}) +``` + + +| Method | Description | +| --- | --- | +| `dispose` | Destroys an element’s collapse. (Removes stored data on the DOM element) | +| `getInstance` | Static method which allows you to get the collapse instance associated to a DOM element, you can use it like this: `bootstrap.Collapse.getInstance(element)`. | +| `getOrCreateInstance` | Static method which returns a collapse instance associated to a DOM element or create a new one in case it wasn’t initialized. You can use it like this: `bootstrap.Collapse.getOrCreateInstance(element)`. | +| `hide` | Hides a collapsible element. **Returns to the caller before the collapsible element has actually been hidden** (e.g., before the `hidden.bs.collapse` event occurs). | +| `show` | Shows a collapsible element. **Returns to the caller before the collapsible element has actually been shown** (e.g., before the `shown.bs.collapse` event occurs). | +| `toggle` | Toggles a collapsible element to shown or hidden. **Returns to the caller before the collapsible element has actually been shown or hidden** (i.e. before the `shown.bs.collapse` or `hidden.bs.collapse` event occurs). | + + +### Events + +Bootstrap’s collapse class exposes a few events for hooking into collapse functionality. + + +| Event type | Description | +| --- | --- | +| `hide.bs.collapse` | This event is fired immediately when the `hide` method has been called. | +| `hidden.bs.collapse` | This event is fired when a collapse element has been hidden from the user (will wait for CSS transitions to complete). | +| `show.bs.collapse` | This event fires immediately when the `show` instance method is called. | +| `shown.bs.collapse` | This event is fired when a collapse element has been made visible to the user (will wait for CSS transitions to complete). | + + +```js +const myCollapsible = document.getElementById('myCollapsible') +myCollapsible.addEventListener('hidden.bs.collapse', event => { + // do something... +}) +``` diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/components/alerts.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/components/alerts.mdx new file mode 100644 index 000000000..e25604462 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/components/alerts.mdx @@ -0,0 +1,218 @@ +--- +title: Alerts +description: Provide contextual feedback messages for typical user actions with the handful of available and flexible alert messages. +toc: true +--- + +import { getData } from '@libs/data' + +## Examples + +Alerts are available for any length of text, as well as an optional close button. For proper styling, use one of the eight **required** contextual classes (e.g., `.alert-success`). For inline dismissal, use the [alerts JavaScript plugin](#dismissing). + + +**Heads up!** As of v5.3.0, the `alert-variant()` Sass mixin is deprecated. Alert variants now have their CSS variables overridden in [a Sass loop](#sass-loops). + + + ``)} /> + + + +### Live example + +Click the button below to show an alert (hidden with inline styles to start), then dismiss (and destroy) it with the built-in close button. + + +`} /> + +We use the following JavaScript to trigger our live alert demo: + + + +### Link color + +Use the `.alert-link` utility class to quickly provide matching colored links within any alert. + + ``)} /> + +### Additional content + +Alerts can also contain additional HTML elements like headings, paragraphs and dividers. + + +

    Well done!

    +

    Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.

    +
    +

    Whenever you need to, be sure to use margin utilities to keep things nice and tidy.

    + `} /> + +### Icons + +Similarly, you can use [flexbox utilities]([[docsref:/utilities/flex]]) and [Bootstrap Icons]([[config:icons]]) to create alerts with icons. Depending on your icons and content, you may want to add more utilities or custom styles. + + + + + +
    + An example alert with an icon +
    + `} /> + +Need more than one icon for your alerts? Consider using more Bootstrap Icons and making a local SVG sprite like so to easily reference the same icons repeatedly. + + + + + + + + + + + + + + + + + `} /> + +### Dismissing + +Using the alert JavaScript plugin, it’s possible to dismiss any alert inline. Here’s how: + +- Be sure you’ve loaded the alert plugin, or the compiled Bootstrap JavaScript. +- Add a [close button]([[docsref:/components/close-button]]) and the `.alert-dismissible` class, which adds extra padding to the right of the alert and positions the close button. +- On the close button, add the `data-bs-dismiss="alert"` attribute, which triggers the JavaScript functionality. Be sure to use the ` + `} /> + + +When an alert is dismissed, the element is completely removed from the page structure. If a keyboard user dismisses the alert using the close button, their focus will suddenly be lost and, depending on the browser, reset to the start of the page/document. For this reason, we recommend including additional JavaScript that listens for the `closed.bs.alert` event and programmatically sets `focus()` to the most appropriate location in the page. If you’re planning to move focus to a non-interactive element that normally does not receive focus, make sure to add `tabindex="-1"` to the element. + + +## CSS + +### Variables + + + +As part of Bootstrap’s evolving CSS variables approach, alerts now use local CSS variables on `.alert` for enhanced real-time customization. Values for the CSS variables are set via Sass, so Sass customization is still supported, too. + + + +### Sass variables + + + +### Sass mixins + + + + + +### Sass loops + +Loop that generates the modifier classes with an overriding of CSS variables. + + + +## JavaScript behavior + +### Initialize + +Initialize elements as alerts + +```js +const alertList = document.querySelectorAll('.alert') +const alerts = [...alertList].map(element => new bootstrap.Alert(element)) +``` + + +For the sole purpose of dismissing an alert, it isn’t necessary to initialize the component manually via the JS API. By making use of `data-bs-dismiss="alert"`, the component will be initialized automatically and properly dismissed. + +See the [triggers](#triggers) section for more details. + + +### Triggers + + + +**Note that closing an alert will remove it from the DOM.** + +### Methods + +You can create an alert instance with the alert constructor, for example: + +```js +const bsAlert = new bootstrap.Alert('#myAlert') +``` + +This makes an alert listen for click events on descendant elements which have the `data-bs-dismiss="alert"` attribute. (Not necessary when using the data-api’s auto-initialization.) + + +| Method | Description | +| --- | --- | +| `close` | Closes an alert by removing it from the DOM. If the `.fade` and `.show` classes are present on the element, the alert will fade out before it is removed. | +| `dispose` | Destroys an element’s alert. (Removes stored data on the DOM element) | +| `getInstance` | Static method which allows you to get the alert instance associated to a DOM element. For example: `bootstrap.Alert.getInstance(alert)`. | +| `getOrCreateInstance` | Static method which returns an alert instance associated to a DOM element or create a new one in case it wasn’t initialized. You can use it like this: `bootstrap.Alert.getOrCreateInstance(element)`. | + + +Basic usage: + +```js +const alert = bootstrap.Alert.getOrCreateInstance('#myAlert') +alert.close() +``` + +### Events + +Bootstrap’s alert plugin exposes a few events for hooking into alert functionality. + + +| Event | Description | +| --- | --- | +| `close.bs.alert` | Fires immediately when the `close` instance method is called. | +| `closed.bs.alert` | Fired when the alert has been closed and CSS transitions have completed. | + + +```js +const myAlert = document.getElementById('myAlert') +myAlert.addEventListener('closed.bs.alert', event => { + // do something, for instance, explicitly move focus to the most appropriate element, + // so it doesn’t get lost/reset to the start of the page + // document.getElementById('...').focus() +}) +``` diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/components/badge.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/components/badge.mdx new file mode 100644 index 000000000..b3e574b6d --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/components/badge.mdx @@ -0,0 +1,83 @@ +--- +title: Badges +description: Documentation and examples for badges, our small count and labeling component. +toc: true +--- + +import { getData } from '@libs/data' + +## Examples + +Badges scale to match the size of the immediate parent element by using relative font sizing and `em` units. As of v5, badges no longer have focus or hover styles for links. + +### Headings + +Example heading New +

    Example heading New

    +

    Example heading New

    +

    Example heading New

    +
    Example heading New
    +
    Example heading New
    `} /> + +### Buttons + +Badges can be used as part of links or buttons to provide a counter. + + + Notifications 4 + `} /> + +Note that depending on how they are used, badges may be confusing for users of screen readers and similar assistive technologies. While the styling of badges provides a visual cue as to their purpose, these users will simply be presented with the content of the badge. Depending on the specific situation, these badges may seem like random additional words or numbers at the end of a sentence, link, or button. + +Unless the context is clear (as with the “Notifications” example, where it is understood that the “4” is the number of notifications), consider including additional context with a visually hidden piece of additional text. + +### Positioned + +Use utilities to modify a `.badge` and position it in the corner of a link or button. + + + Inbox + + 99+ + unread messages + + `} /> + +You can also replace the `.badge` class with a few more utilities without a count for a more generic indicator. + + + Profile + + New alerts + + `} /> + +## Background colors + + + +Set a `background-color` with contrasting foreground `color` with [our `.text-bg-{color}` helpers]([[docsref:helpers/color-background]]). Previously it was required to manually pair your choice of [`.text-{color}`]([[docsref:/utilities/colors]]) and [`.bg-{color}`]([[docsref:/utilities/background]]) utilities for styling, which you still may use if you prefer. + + `${themeColor.title}`)} /> + + + +## Pill badges + +Use the `.rounded-pill` utility class to make badges more rounded with a larger `border-radius`. + + `${themeColor.title}`)} /> + +## CSS + +### Variables + + + +As part of Bootstrap’s evolving CSS variables approach, badges now use local CSS variables on `.badge` for enhanced real-time customization. Values for the CSS variables are set via Sass, so Sass customization is still supported, too. + + + +### Sass variables + + diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/components/breadcrumb.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/components/breadcrumb.mdx new file mode 100644 index 000000000..50cceb1cc --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/components/breadcrumb.mdx @@ -0,0 +1,98 @@ +--- +title: Breadcrumb +description: Indicate the current page’s location within a navigational hierarchy that automatically adds separators via CSS. +toc: true +--- + +## Example + +Use an ordered or unordered list with linked list items to create a minimally styled breadcrumb. Use our utilities to add additional styles as desired. + + + + + + + + `} /> + +## Dividers + +Dividers are automatically added in CSS through [`::before`](https://developer.mozilla.org/en-US/docs/Web/CSS/::before) and [`content`](https://developer.mozilla.org/en-US/docs/Web/CSS/content). They can be changed by modifying a local CSS custom property `--bs-breadcrumb-divider`, or through the `$breadcrumb-divider` Sass variable — and `$breadcrumb-divider-flipped` for its RTL counterpart, if needed. We default to our Sass variable, which is set as a fallback to the custom property. This way, you get a global divider that you can override without recompiling CSS at any time. + + + + `} /> + +When modifying via Sass, the [quote](https://sass-lang.com/documentation/modules/string/#quote) function is required to generate the quotes around a string. For example, using `>` as the divider, you can use this: + +```scss +$breadcrumb-divider: quote(">"); +``` + +It’s also possible to use an **embedded SVG icon**. Apply it via our CSS custom property, or use the Sass variable. + + +**Inlined SVG requires properly escaped characters.** Some reserved characters, such as `<`, `>` and `#`, must be URL-encoded or escaped. We do this with the `$breadcrumb-divider` variable using our [`escape-svg()` Sass function]([[docsref:/customize/sass#escape-svg]]). When customizing the CSS variable, you must handle this yourself. Read [Kevin Weber’s explanations on CodePen](https://codepen.io/kevinweber/pen/dXWoRw ) for more info. + + + + + `} /> + +```scss +$breadcrumb-divider: url("data:image/svg+xml,"); +``` + +You can also remove the divider setting `--bs-breadcrumb-divider: '';` (empty strings in CSS custom properties counts as a value), or setting the Sass variable to `$breadcrumb-divider: none;`. + + + + `} /> + + +```scss +$breadcrumb-divider: none; +``` + +## Accessibility + +Since breadcrumbs provide a navigation, it’s a good idea to add a meaningful label such as `aria-label="breadcrumb"` to describe the type of navigation provided in the ``} /> + +## Directions + + +**Directions are flipped in RTL mode.** As such, `.dropstart` will appear on the right side. + + +### Centered + +Make the dropdown menu centered below the toggle with `.dropdown-center` on the parent element. + + + + + `} /> + +### Dropup + +Trigger dropdown menus above elements by adding `.dropup` to the parent element. + + + + + +
    + + + +
    `} /> + +```html + +
    + + +
    + + +
    + + + +
    +``` + +### Dropup centered + +Make the dropup menu centered above the toggle with `.dropup-center` on the parent element. + + + + + `} /> + +### Dropend + +Trigger dropdown menus at the right of the elements by adding `.dropend` to the parent element. + + + + + +
    + + + +
    `} /> + +```html + +
    + + +
    + + +
    + + + +
    +``` + +### Dropstart + +Trigger dropdown menus at the left of the elements by adding `.dropstart` to the parent element. + + + + + +
    + + + +
    `} /> + +```html + +
    + + +
    + + +
    + + + +
    +``` + +## Menu items + +You can use `` or ` + + `} /> + +You can also create non-interactive dropdown items with `.dropdown-item-text`. Feel free to style further with custom CSS or text utilities. + + +
  • Dropdown item text
  • +
  • Action
  • +
  • Another action
  • +
  • Something else here
  • + `} /> + +### Active + +Add `.active` to items in the dropdown to **style them as active**. To convey the active state to assistive technologies, use the `aria-current` attribute — using the `page` value for the current page, or `true` for the current item in a set. + + +
  • Regular link
  • +
  • Active link
  • +
  • Another link
  • + `} /> + +### Disabled + +Add `.disabled` to items in the dropdown to **style them as disabled**. + + +
  • Regular link
  • +
  • Disabled link
  • +
  • Another link
  • + `} /> + +## Menu alignment + +By default, a dropdown menu is automatically positioned 100% from the top and along the left side of its parent. You can change this with the directional `.drop*` classes, but you can also control them with additional modifier classes. + +Add `.dropdown-menu-end` to a `.dropdown-menu` to right align the dropdown menu. Directions are mirrored when using Bootstrap in RTL, meaning `.dropdown-menu-end` will appear on the left side. + + +**Heads up!** Dropdowns are positioned thanks to Popper except when they are contained in a navbar. + + + + + + `} /> + +### Responsive alignment + +If you want to use responsive alignment, disable dynamic positioning by adding the `data-bs-display="static"` attribute and use the responsive variation classes. + +To align **right** the dropdown menu with the given breakpoint or larger, add `.dropdown-menu{-sm|-md|-lg|-xl|-xxl}-end`. + + + + + `} /> + +To align **left** the dropdown menu with the given breakpoint or larger, add `.dropdown-menu-end` and `.dropdown-menu{-sm|-md|-lg|-xl|-xxl}-start`. + + + + + `} /> + +Note that you don’t need to add a `data-bs-display="static"` attribute to dropdown buttons in navbars, since Popper isn’t used in navbars. + +### Alignment options + +Taking most of the options shown above, here’s a small kitchen sink demo of various dropdown alignment options in one place. + + + + + + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    `} /> + +## Menu content + +### Headers + +Add a header to label sections of actions in any dropdown menu. + + +
  • +
  • Action
  • +
  • Another action
  • + `} /> + +### Dividers + +Separate groups of related menu items with a divider. + + +
  • Action
  • +
  • Another action
  • +
  • Something else here
  • +
  • +
  • Separated link
  • + `} /> + +### Text + +Place any freeform text within a dropdown menu with text and use [spacing utilities]([[docsref:/utilities/spacing]]). Note that you’ll likely need additional sizing styles to constrain the menu width. + + +

    + Some example text that’s free-flowing within the dropdown menu. +

    +

    + And this is more example text. +

    + `} /> + +### Forms + +Put a form within a dropdown menu, or make it into a dropdown menu, and use [margin or padding utilities]([[docsref:/utilities/spacing]]) to give it the negative space you require. + + +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    + +
    + + New around here? Sign up + Forgot password? + `} /> + + + + + `} /> + +## Dropdown options + +Use `data-bs-offset` or `data-bs-reference` to change the location of the dropdown. + + + +
    + + + +
    + `} /> + +### Auto close behavior + +By default, the dropdown menu is closed when clicking inside or outside the dropdown menu. You can use the `autoClose` option to change this behavior of the dropdown. + + + + + + +
    + + +
    + +
    + + +
    + +
    + + +
    `} /> + +## CSS + +### Variables + + + +As part of Bootstrap’s evolving CSS variables approach, dropdowns now use local CSS variables on `.dropdown-menu` for enhanced real-time customization. Values for the CSS variables are set via Sass, so Sass customization is still supported, too. + + + + +Dropdown items include at least one variable that is not set on `.dropdown`. This allows you to provide a new value while Bootstrap defaults to a fallback value. + +- `--bs-dropdown-item-border-radius` + + +Customization through CSS variables can be seen on the `.dropdown-menu-dark` class where we override specific values without adding duplicate CSS selectors. + + + +### Sass variables + +Variables for all dropdowns: + + + +Variables for the [dark dropdown](#dark-dropdowns): + + + +Variables for the CSS-based carets that indicate a dropdown’s interactivity: + + + +### Sass mixins + +Mixins are used to generate the CSS-based carets and can be found in `scss/mixins/_caret.scss`. + + + +## Usage + +Via data attributes or JavaScript, the dropdown plugin toggles hidden content (dropdown menus) by toggling the `.show` class on the parent `.dropdown-menu`. The `data-bs-toggle="dropdown"` attribute is relied on for closing dropdown menus at an application level, so it’s a good idea to always use it. + + +On touch-enabled devices, opening a dropdown adds empty `mouseover` handlers to the immediate children of the `` element. This admittedly ugly hack is necessary to work around a [quirk in iOs’ event delegation](https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html), which would otherwise prevent a tap anywhere outside of the dropdown from triggering the code that closes the dropdown. Once the dropdown is closed, these additional empty `mouseover` handlers are removed. + + +### Via data attributes + +Add `data-bs-toggle="dropdown"` to a link or button to toggle a dropdown. + +```html + +``` + +### Via JavaScript + + +Dropdowns must have `data-bs-toggle="dropdown"` on their trigger element, regardless of whether you call your dropdown via JavaScript or use the data-api. + + +Call the dropdowns via JavaScript: + +```js +const dropdownElementList = document.querySelectorAll('.dropdown-toggle') +const dropdownList = [...dropdownElementList].map(dropdownToggleEl => new bootstrap.Dropdown(dropdownToggleEl)) +``` + +### Options + + + + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `autoClose` | boolean, string | `true` | Configure the auto close behavior of the dropdown:
    • `true` - the dropdown will be closed by clicking outside or inside the dropdown menu.
    • `false` - the dropdown will be closed by clicking the toggle button and manually calling `hide` or `toggle` method. (Also will not be closed by pressing Esc key)
    • `'inside'` - the dropdown will be closed (only) by clicking inside the dropdown menu.
    • `'outside'` - the dropdown will be closed (only) by clicking outside the dropdown menu.
    Note: the dropdown can always be closed with the Esc key. | +| `boundary` | string, element | `'clippingParents'` | Overflow constraint boundary of the dropdown menu (applies only to Popper’s preventOverflow modifier). By default it’s `clippingParents` and can accept an HTMLElement reference (via JavaScript only). For more information refer to Popper’s [detectOverflow docs](https://popper.js.org/docs/v2/utils/detect-overflow/#boundary). | +| `display` | string | `'dynamic'` | By default, we use Popper for dynamic positioning. Disable this with `static`. | +| `offset` | array, string, function | `[0, 2]` | Offset of the dropdown relative to its target. You can pass a string in data attributes with comma separated values like: `data-bs-offset="10,20"`. When a function is used to determine the offset, it is called with an object containing the popper placement, the reference, and popper rects as its first argument. The triggering element DOM node is passed as the second argument. The function must return an array with two numbers: [skidding](https://popper.js.org/docs/v2/modifiers/offset/#skidding-1), [distance](https://popper.js.org/docs/v2/modifiers/offset/#distance-1). For more information refer to Popper’s [offset docs](https://popper.js.org/docs/v2/modifiers/offset/#options). | +| `popperConfig` | null, object, function | `null` | To change Bootstrap’s default Popper config, see [Popper’s configuration](https://popper.js.org/docs/v2/constructors/#options). When a function is used to create the Popper configuration, it’s called with an object that contains the Bootstrap’s default Popper configuration. It helps you use and merge the default with your own configuration. The function must return a configuration object for Popper. | +| `reference` | string, element, object | `'toggle'` | Reference element of the dropdown menu. Accepts the values of `'toggle'`, `'parent'`, an HTMLElement reference or an object providing `getBoundingClientRect`. For more information refer to Popper’s [constructor docs](https://popper.js.org/docs/v2/constructors/#createpopper) and [virtual element docs](https://popper.js.org/docs/v2/virtual-elements/). | +
    + +#### Using function with `popperConfig` + +```js +const dropdown = new bootstrap.Dropdown(element, { + popperConfig(defaultBsPopperConfig) { + // const newPopperConfig = {...} + // use defaultBsPopperConfig if needed... + // return newPopperConfig + } +}) +``` + +### Methods + + +| Method | Description | +| --- | --- | +| `dispose` | Destroys an element’s dropdown. (Removes stored data on the DOM element) | +| `getInstance` | Static method which allows you to get the dropdown instance associated to a DOM element, you can use it like this: `bootstrap.Dropdown.getInstance(element)`. | +| `getOrCreateInstance` | Static method which returns a dropdown instance associated to a DOM element or create a new one in case it wasn’t initialized. You can use it like this: `bootstrap.Dropdown.getOrCreateInstance(element)`. | +| `hide` | Hides the dropdown menu of a given navbar or tabbed navigation. | +| `show` | Shows the dropdown menu of a given navbar or tabbed navigation. | +| `toggle` | Toggles the dropdown menu of a given navbar or tabbed navigation. | +| `update` | Updates the position of an element’s dropdown. | + + +### Events + +All dropdown events are fired at the toggling element and then bubbled up. So you can also add event listeners on the `.dropdown-menu`’s parent element. `hide.bs.dropdown` and `hidden.bs.dropdown` events have a `clickEvent` property (only when the original Event type is `click`) that contains an Event Object for the click event. + + +| Event type | Description | +| --- | --- | +| `hide.bs.dropdown` | Fires immediately when the `hide` instance method has been called. | +| `hidden.bs.dropdown` | Fired when the dropdown has finished being hidden from the user and CSS transitions have completed. | +| `show.bs.dropdown` | Fires immediately when the `show` instance method is called. | +| `shown.bs.dropdown` | Fired when the dropdown has been made visible to the user and CSS transitions have completed. | + + +```js +const myDropdown = document.getElementById('myDropdown') +myDropdown.addEventListener('show.bs.dropdown', event => { + // do something... +}) +``` diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/components/list-group.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/components/list-group.mdx new file mode 100644 index 000000000..59827ddd4 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/components/list-group.mdx @@ -0,0 +1,448 @@ +--- +title: List group +description: List groups are a flexible and powerful component for displaying a series of content. Modify and extend them to support just about any content within. +toc: true +--- + +import { getData } from '@libs/data' + +## Basic example + +The most basic list group is an unordered list with list items and the proper classes. Build upon it with the options that follow, or with your own CSS as needed. + + +
  • An item
  • +
  • A second item
  • +
  • A third item
  • +
  • A fourth item
  • +
  • And a fifth one
  • + `} /> + +## Active items + +Add `.active` to a `.list-group-item` to indicate the current active selection. + + +
  • An active item
  • +
  • A second item
  • +
  • A third item
  • +
  • A fourth item
  • +
  • And a fifth one
  • + `} /> + +## Links and buttons + +Use ``s or ` + + + + + `} /> + +## Flush + +Add `.list-group-flush` to remove some borders and rounded corners to render list group items edge-to-edge in a parent container (e.g., cards). + + +
  • An item
  • +
  • A second item
  • +
  • A third item
  • +
  • A fourth item
  • +
  • And a fifth one
  • + `} /> + +## Numbered + +Add the `.list-group-numbered` modifier class (and optionally use an `
      ` element) to opt into numbered list group items. Numbers are generated via CSS (as opposed to a `
        `s default browser styling) for better placement inside list group items and to allow for better customization. + +Numbers are generated by `counter-reset` on the `
          `, and then styled and placed with a `::before` pseudo-element on the `
        1. ` with `counter-increment` and `content`. + + +
        2. A list item
        3. +
        4. A list item
        5. +
        6. A list item
        7. +
        `} /> + +These work great with custom content as well. + + +
      1. +
        +
        Subheading
        + Content for list item +
        + 14 +
      2. +
      3. +
        +
        Subheading
        + Content for list item +
        + 14 +
      4. +
      5. +
        +
        Subheading
        + Content for list item +
        + 14 +
      6. +
      `} /> + +## Horizontal + +Add `.list-group-horizontal` to change the layout of list group items from vertical to horizontal across all breakpoints. Alternatively, choose a responsive variant `.list-group-horizontal-{sm|md|lg|xl|xxl}` to make a list group horizontal starting at that breakpoint’s `min-width`. Currently **horizontal list groups cannot be combined with flush list groups.** + +**ProTip:** Want equal-width list group items when horizontal? Add `.flex-fill` to each list group item. + + `
        +
      • An item
      • +
      • A second item
      • +
      • A third item
      • +
      `)} /> + +## Variants + + +**Heads up!** As of v5.3.0, the `list-group-item-variant()` Sass mixin is deprecated. List group item variants now have their CSS variables overridden in [a Sass loop](#sass-loops). + + +Use contextual classes to style list items with a stateful background and color. + + +
    1. A simple default list group item
    2. + `, + ...getData('theme-colors').map((themeColor) => `
    3. A simple ${themeColor.name} list group item
    4. `), + `` + ]} /> + +### For links and buttons + +Contextual classes also work with `.list-group-item-action` for `
      ` and ` + + + + + + + + +```html + +``` + + +In the above static example, we use `
      `, to avoid issues with the heading hierarchy in the documentation page. Structurally, however, a modal dialog represents its own separate document/context, so the `.modal-title` should ideally be an `

      `. If necessary, you can use the [font size utilities]([[docsref:/utilities/text#font-size]]) to control the heading’s appearance. All the following live examples use this approach. + + +### Live demo + +Toggle a working modal demo by clicking the button below. It will slide down and fade in from the top of the page. + + + +
      + +
      + +```html + + + + + +``` + +### Static backdrop + +When backdrop is set to static, the modal will not close when clicking outside of it. Click the button below to try it. + + + +
      + +
      + +```html + + + + + +``` + +### Scrolling long content + +When modals become too long for the user’s viewport or device, they scroll independent of the page itself. Try the demo below to see what we mean. + + + +
      + +
      + +You can also create a scrollable modal that allows scrolling the modal body by adding `.modal-dialog-scrollable` to `.modal-dialog`. + + + +
      + +
      + +```html + + +``` + +### Vertically centered + +Add `.modal-dialog-centered` to `.modal-dialog` to vertically center the modal. + +

      `} /> + +## Display headings + +Traditional heading elements are designed to work best in the meat of your page content. When you need a heading to stand out, consider using a **display heading**—a larger, slightly more opinionated heading style. + +
      +
      Display 1
      +
      Display 2
      +
      Display 3
      +
      Display 4
      +
      Display 5
      +
      Display 6
      +
      + +```html +

      Display 1

      +

      Display 2

      +

      Display 3

      +

      Display 4

      +

      Display 5

      +

      Display 6

      +``` + +Display headings are configured via the `$display-font-sizes` Sass map and two variables, `$display-font-weight` and `$display-line-height`. + +Display headings are customizable via two variables, `$display-font-family` and `$display-font-style`. + + + +## Lead + +Make a paragraph stand out by adding `.lead`. + + + This is a lead paragraph. It stands out from regular paragraphs. +

      `} /> + +## Inline text elements + +Styling for common inline HTML5 elements. + +You can use the mark tag to highlight text.

      +

      This line of text is meant to be treated as deleted text.

      +

      This line of text is meant to be treated as no longer accurate.

      +

      This line of text is meant to be treated as an addition to the document.

      +

      This line of text will render as underlined.

      +

      This line of text is meant to be treated as fine print.

      +

      This line rendered as bold text.

      +

      This line rendered as italicized text.

      `} /> + +Beware that those tags should be used for semantic purpose: + +- `` represents text which is marked or highlighted for reference or notation purposes. +- `` represents side-comments and small print, like copyright and legal text. +- `` represents element that are no longer relevant or no longer accurate. +- `` represents a span of inline text which should be rendered in a way that indicates that it has a non-textual annotation. + +If you want to style your text, you should use the following classes instead: + +- `.mark` will apply the same styles as ``. +- `.small` will apply the same styles as ``. +- `.text-decoration-underline` will apply the same styles as ``. +- `.text-decoration-line-through` will apply the same styles as ``. + +While not shown above, feel free to use `` and `` in HTML5. `` is meant to highlight words or phrases without conveying additional importance, while `` is mostly for voice, technical terms, etc. + +## Text utilities + +Change text alignment, transform, style, weight, line-height, decoration and color with our [text utilities]([[docsref:/utilities/text]]) and [color utilities]([[docsref:/utilities/colors]]). + +## Abbreviations + +Stylized implementation of HTML’s `` element for abbreviations and acronyms to show the expanded version on hover. Abbreviations have a default underline and gain a help cursor to provide additional context on hover and to users of assistive technologies. + +Add `.initialism` to an abbreviation for a slightly smaller font-size. + +attr

      +

      HTML

      `} /> + +## Blockquotes + +For quoting blocks of content from another source within your document. Wrap `
      ` around any HTML as the quote. + + +

      A well-known quote, contained in a blockquote element.

      +
      `} /> + +### Naming a source + +The HTML spec requires that blockquote attribution be placed outside the `
      `. When providing attribution, wrap your `
      ` in a `
      ` and use a `
      ` or a block level element (e.g., `

      `) with the `.blockquote-footer` class. Be sure to wrap the name of the source work in `` as well. + + +

      +

      A well-known quote, contained in a blockquote element.

      +
      + +
      `} /> + +### Alignment + +Use text utilities as needed to change the alignment of your blockquote. + + +
      +

      A well-known quote, contained in a blockquote element.

      +
      + + `} /> + + +
      +

      A well-known quote, contained in a blockquote element.

      +
      + + `} /> + +## Lists + +### Unstyled + +Remove the default `list-style` and left margin on list items (immediate children only). **This only applies to immediate children list items**, meaning you will need to add the class for any nested lists as well. + + +
    5. This is a list.
    6. +
    7. It appears completely unstyled.
    8. +
    9. Structurally, it’s still a list.
    10. +
    11. However, this style only applies to immediate child elements.
    12. +
    13. Nested lists: +
        +
      • are unaffected by this style
      • +
      • will still show a bullet
      • +
      • and have appropriate left margin
      • +
      +
    14. +
    15. This may still come in handy in some situations.
    16. + `} /> + +### Inline + +Remove a list’s bullets and apply some light `margin` with a combination of two classes, `.list-inline` and `.list-inline-item`. + + +
    17. This is a list item.
    18. +
    19. And another one.
    20. +
    21. But they’re displayed inline.
    22. + `} /> + +### Description list alignment + +Align terms and descriptions horizontally by using our grid system’s predefined classes (or semantic mixins). For longer terms, you can optionally add a `.text-truncate` class to truncate the text with an ellipsis. + + +
      Description lists
      +
      A description list is perfect for defining terms.
      + +
      Term
      +
      +

      Definition for the term.

      +

      And some more placeholder definition text.

      +
      + +
      Another term
      +
      This definition is short, so no extra paragraphs or anything.
      + +
      Truncated term is truncated
      +
      This can be useful when space is tight. Adds an ellipsis at the end.
      + +
      Nesting
      +
      +
      +
      Nested definition list
      +
      I heard you like definition lists. Let me put a definition list inside your definition list.
      +
      +
      + `} /> + +## Responsive font sizes + +In Bootstrap 5, we’ve enabled responsive font sizes by default, allowing text to scale more naturally across device and viewport sizes. Have a look at the [RFS page]([[docsref:/getting-started/rfs]]) to find out how this works. + +## CSS + +### Sass variables + +Headings have some dedicated variables for sizing and spacing. + + + +Miscellaneous typography elements covered here and in [Reboot]([[docsref:/content/reboot]]) also have dedicated variables. + + + +### Sass mixins + +There are no dedicated mixins for typography, but Bootstrap does use [Responsive Font Sizing (RFS)]([[docsref:/getting-started/rfs]]). diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/color-modes.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/color-modes.mdx new file mode 100644 index 000000000..79dd7f6a4 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/color-modes.mdx @@ -0,0 +1,253 @@ +--- +title: Color modes +description: Bootstrap now supports color modes, or themes, as of v5.3.0. Explore our default light color mode and the new dark mode, or create your own using our styles as your template. +toc: true +added: + version: "5.3" +--- + +import { getDocsRelativePath } from '@libs/path' + + +**Try it yourself!** Download the source code and working demo for using Bootstrap with Stylelint, and the color modes from the [twbs/examples repository](https://github.com/twbs/examples/tree/main/color-modes). You can also [open the example in StackBlitz](https://stackblitz.com/github/twbs/examples/tree/main/color-modes?file=index.html). + + +## Dark mode + +**Bootstrap now supports color modes, starting with dark mode!** With v5.3.0 you can implement your own color mode toggler (see below for an example from Bootstrap’s docs) and apply the different color modes as you see fit. We support a light mode (default) and now dark mode. Color modes can be toggled globally on the `` element, or on specific components and elements, thanks to the `data-bs-theme` attribute. + +Alternatively, you can also switch to a media query implementation thanks to our color mode mixin—see [the usage section for details](#building-with-sass). Heads up though—this eliminates your ability to change themes on a per-component basis as shown below. + +## Example + +For example, to change the color mode of a dropdown menu, add `data-bs-theme="light"` or `data-bs-theme="dark"` to the parent `.dropdown`. Now, no matter the global color mode, these dropdowns will display with the specified theme value. + + + + + + + `} /> + +## How it works + +- As shown above, color mode styles are controlled by the `data-bs-theme` attribute. This attribute can be applied to the `` element, or to any other element or Bootstrap component. If applied to the `` element, it will apply to everything. If applied to a component or element, it will be scoped to that specific component or element. + +- For each color mode you wish to support, you’ll need to add new overrides for the shared global CSS variables. We do this already in our `_root.scss` stylesheet for dark mode, with light mode being the default values. In writing color mode specific styles, use the mixin: + + ```scss + // Color mode variables in _root.scss + @include color-mode(dark) { + // CSS variable overrides here... + } + ``` + +- We use a custom `_variables-dark.scss` to power those shared global CSS variable overrides for dark mode. This file isn’t required for your own custom color modes, but it’s required for our dark mode for two reasons. First, it’s better to have a single place to reset global colors. Second, some Sass variables had to be overridden for background images embedded in our CSS for accordions, form components, and more. + +## Usage + +### Enable dark mode + +Enable the built in dark color mode across your entire project by adding the `data-bs-theme="dark"` attribute to the `` element. This will apply the dark color mode to all components and elements, other than those with a specific `data-bs-theme` attribute applied. Building on the [quick start template]([[docsref:/getting-started/introduction#quick-start]]): + +```html + + + + + + Bootstrap demo + + + +

      Hello, world!

      + + + +``` + +Bootstrap does not yet ship with a built-in color mode picker, but you can use the one from our own documentation if you like. [Learn more in the JavaScript section.](#javascript) + +### Building with Sass + +Our new dark mode option is available to use for all users of Bootstrap, but it’s controlled via data attributes instead of media queries and does not automatically toggle your project’s color mode. You can disable our dark mode entirely via Sass by changing `$enable-dark-mode` to `false`. + +We use a custom Sass mixin, `color-mode()`, to help you control _how_ color modes are applied. By default, we use a `data` attribute approach, allowing you to create more user-friendly experiences where your visitors can choose to have an automatic dark mode or control their preference (like in our own docs here). This is also an easy and scalable way to add different themes and more custom color modes beyond light and dark. + +In case you want to use media queries and only make color modes automatic, you can change the mixin’s default type via Sass variable. Consider the following snippet and its compiled CSS output. + +```scss +$color-mode-type: data; + +@include color-mode(dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } +} +``` + +Outputs to: + +```css +[data-bs-theme=dark] .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); +} +``` + +And when setting to `media-query`: + +```scss +$color-mode-type: media-query; + +@include color-mode(dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } +} +``` + +Outputs to: + +```css +@media (prefers-color-scheme: dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } +} +``` + +## Custom color modes + +While the primary use case for color modes is light and dark mode, custom color modes are also possible. Create your own `data-bs-theme` selector with a custom value as the name of your color mode, then modify our Sass and CSS variables as needed. We opted to create a separate `_variables-dark.scss` stylesheet to house Bootstrap’s dark mode specific Sass variables, but that’s not required for you. + +For example, you can create a “blue theme” with the selector `data-bs-theme="blue"`. In your custom Sass or CSS file, add the new selector and override any global or component CSS variables as needed. If you’re using Sass, you can also use Sass’s functions within your CSS variable overrides. + + + + +
      Example blue theme
      +

      Some paragraph text to show how the blue theme might look with written copy.

      + +
      + + +`} /> + +```html +
      + ... +
      +``` + +## JavaScript + +To allow visitors or users to toggle color modes, you’ll need to create a toggle element to control the `data-bs-theme` attribute on the root element, ``. We’ve built a toggler in our documentation that initially defers to a user’s current system color mode, but provides an option to override that and pick a specific color mode. + +Here’s a look at the JavaScript that powers it. Feel free to inspect our own documentation navbar to see how it’s implemented using HTML and CSS from our own components. It is suggested to include the JavaScript at the top of your page to reduce potential screen flickering during reloading of your site. Note that if you decide to use media queries for your color modes, your JavaScript may need to be modified or removed if you prefer an implicit control. + + + +## Adding theme colors + +Adding a new color in `$theme-colors` is not enough for some of our components like [alerts]([[docsref:/components/alerts]]) and [list groups]([[docsref:/components/list-group]]). New colors must also be defined in `$theme-colors-text`, `$theme-colors-bg-subtle`, and `$theme-colors-border-subtle` for light theme; but also in `$theme-colors-text-dark`, `$theme-colors-bg-subtle-dark`, and `$theme-colors-border-subtle-dark` for dark theme. + +This is a manual process because Sass cannot generate its own Sass variables from an existing variable or map. In future versions of Bootstrap, we'll revisit this setup to reduce the duplication. + +```scss +// Required +@import "functions"; +@import "variables"; +@import "variables-dark"; + +// Add a custom color to $theme-colors +$custom-colors: ( + "custom-color": #712cf9 +); +$theme-colors: map-merge($theme-colors, $custom-colors); + +@import "maps"; +@import "mixins"; +@import "utilities"; + +// Add a custom color to new theme maps + +// Light mode +$custom-colors-text: ("custom-color": #712cf9); +$custom-colors-bg-subtle: ("custom-color": #e1d2fe); +$custom-colors-border-subtle: ("custom-color": #bfa1fc); + +$theme-colors-text: map-merge($theme-colors-text, $custom-colors-text); +$theme-colors-bg-subtle: map-merge($theme-colors-bg-subtle, $custom-colors-bg-subtle); +$theme-colors-border-subtle: map-merge($theme-colors-border-subtle, $custom-colors-border-subtle); + +// Dark mode +$custom-colors-text-dark: ("custom-color": #e1d2f2); +$custom-colors-bg-subtle-dark: ("custom-color": #8951fa); +$custom-colors-border-subtle-dark: ("custom-color": #e1d2f2); + +$theme-colors-text-dark: map-merge($theme-colors-text-dark, $custom-colors-text-dark); +$theme-colors-bg-subtle-dark: map-merge($theme-colors-bg-subtle-dark, $custom-colors-bg-subtle-dark); +$theme-colors-border-subtle-dark: map-merge($theme-colors-border-subtle-dark, $custom-colors-border-subtle-dark); + +// Remainder of Bootstrap imports +@import "root"; +@import "reboot"; +// etc +``` + +## CSS + +### Variables + +Dozens of root level CSS variables are repeated as overrides for dark mode. These are scoped to the color mode selector, which defaults to `data-bs-theme` but [can be configured](#building-with-sass) to use a `prefers-color-scheme` media query. Use these variables as a guideline for generating your own new color modes. + + + +### Sass variables + +CSS variables for our dark color mode are partially generated from dark mode specific Sass variables in `_variables-dark.scss`. This also includes some custom overrides for changing the colors of embedded SVGs used throughout our components. + + + +### Sass mixins + +Styles for dark mode, and any custom color modes you create, can be scoped appropriately to the `data-bs-theme` attribute selector or media query with the customizable `color-mode()` mixin. See the [Sass usage section](#building-with-sass) for more details. + + diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/color.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/color.mdx new file mode 100644 index 000000000..b24f14d6b --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/color.mdx @@ -0,0 +1,513 @@ +--- +title: Color +description: Bootstrap is supported by an extensive color system that themes our styles and components. This enables more comprehensive customization and extension for any project. +toc: true +--- + +import { getData } from '@libs/data' +import { getSequence } from '@libs/utils' + +## Colors + + + +Bootstrap’s color palette has continued to expand and become more nuanced in v5.3.0. We’ve added new variables for `secondary` and `tertiary` text and background colors, plus `{color}-bg-subtle`, `{color}-border-subtle`, and `{color}-text-emphasis` for our theme colors. These new colors are available through Sass and CSS variables (but not our color maps or utility classes) with the express goal of making it easier to customize across multiple colors modes like light and dark. These new variables are globally set on `:root` and are adapted for our new dark color mode while our original theme colors remain unchanged. + +Colors ending in `-rgb` provide the `red, green, blue` values for use in `rgb()` and `rgba()` color modes. For example, `rgba(var(--bs-secondary-bg-rgb), .5)`. + + +**Heads up!** There’s some potential confusion with our new secondary and tertiary colors, and our existing secondary theme color, as well as our light and dark theme colors. Expect this to be ironed out in v6. + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      DescriptionSwatchVariables
      + **Body —** Default foreground (color) and background, including components. + +
       
      +
      + `--bs-body-color`
      `--bs-body-color-rgb` +
      +
       
      +
      + `--bs-body-bg`
      `--bs-body-bg-rgb` +
      + **Secondary —** Use the `color` option for lighter text. Use the `bg` option for dividers and to indicate disabled component states. + +
       
      +
      + `--bs-secondary-color`
      `--bs-secondary-color-rgb` +
      +
       
      +
      + `--bs-secondary-bg`
      `--bs-secondary-bg-rgb` +
      + **Tertiary —** Use the `color` option for even lighter text. Use the `bg` option to style backgrounds for hover states, accents, and wells. + +
       
      +
      + `--bs-tertiary-color`
      `--bs-tertiary-color-rgb` +
      +
       
      +
      + `--bs-tertiary-bg`
      `--bs-tertiary-bg-rgb` +
      + **Emphasis —** For higher contrast text. Not applicable for backgrounds. + +
       
      +
      + `--bs-emphasis-color`
      `--bs-emphasis-color-rgb` +
      + **Border —** For component borders, dividers, and rules. Use `--bs-border-color-translucent` to blend with backgrounds with an `rgba()` value. + +
       
      +
      + `--bs-border-color`
      `--bs-border-color-rgb` +
      + **Primary —** Main theme color, used for hyperlinks, focus styles, and component and form active states. + +
       
      +
      + `--bs-primary`
      `--bs-primary-rgb` +
      +
       
      +
      + `--bs-primary-bg-subtle` +
      +
       
      +
      + `--bs-primary-border-subtle` +
      +
      Text
      +
      + `--bs-primary-text-emphasis` +
      + **Success —** Theme color used for positive or successful actions and information. + +
       
      +
      + `--bs-success`
      `--bs-success-rgb` +
      +
       
      +
      + `--bs-success-bg-subtle` +
      +
       
      +
      + `--bs-success-border-subtle` +
      +
      Text
      +
      + `--bs-success-text-emphasis` +
      + **Danger —** Theme color used for errors and dangerous actions. + +
       
      +
      + `--bs-danger`
      `--bs-danger-rgb` +
      +
       
      +
      + `--bs-danger-bg-subtle` +
      +
       
      +
      + `--bs-danger-border-subtle` +
      +
      Text
      +
      + `--bs-danger-text-emphasis` +
      + **Warning —** Theme color used for non-destructive warning messages. + +
       
      +
      + `--bs-warning`
      `--bs-warning-rgb` +
      +
       
      +
      + `--bs-warning-bg-subtle` +
      +
       
      +
      + `--bs-warning-border-subtle` +
      +
      Text
      +
      + `--bs-warning-text-emphasis` +
      + **Info —** Theme color used for neutral and informative content. + +
       
      +
      + `--bs-info`
      `--bs-info-rgb` +
      +
       
      +
      + `--bs-info-bg-subtle` +
      +
       
      +
      + `--bs-info-border-subtle` +
      +
      Text
      +
      + `--bs-info-text-emphasis` +
      + **Light —** Additional theme option for less contrasting colors. + +
       
      +
      + `--bs-light`
      `--bs-light-rgb` +
      +
       
      +
      + `--bs-light-bg-subtle` +
      +
       
      +
      + `--bs-light-border-subtle` +
      +
      Text
      +
      + `--bs-light-text-emphasis` +
      + **Dark —** Additional theme option for higher contrasting colors. + +
       
      +
      + `--bs-dark`
      `--bs-dark-rgb` +
      +
       
      +
      + `--bs-dark-bg-subtle` +
      +
       
      +
      + `--bs-dark-border-subtle` +
      +
      Text
      +
      + `--bs-dark-text-emphasis` +
      +
      + +### Using the new colors + +These new colors are accessible via CSS variables and utility classes—like `--bs-primary-bg-subtle` and `.bg-primary-subtle`—allowing you to compose your own CSS rules with the variables, or to quickly apply styles via classes. The utilities are built with the color’s associated CSS variables, and since we customize those CSS variables for dark mode, they are also adaptive to color mode by default. + + + Example element with utilities + `} /> + +### Theme colors + +We use a subset of all colors to create a smaller color palette for generating color schemes, also available as Sass variables and a Sass map in Bootstrap’s `scss/_variables.scss` file. + +
      + {getData('theme-colors').map((themeColor) => { + return ( +
      +
      {themeColor.title}
      +
      + ) + })} +
      + +All these colors are available as a Sass map, `$theme-colors`. + + + +Check out [our Sass maps and loops docs]([[docsref:/customize/sass#maps-and-loops]]) for how to modify these colors. + +### All colors + +All Bootstrap colors are available as Sass variables and a Sass map in `scss/_variables.scss` file. To avoid increased file sizes, we don’t create text or background color classes for each of these variables. Instead, we choose a subset of these colors for a [theme palette](#theme-colors). + +Be sure to monitor contrast ratios as you customize colors. As shown below, we’ve added three contrast ratios to each of the main colors—one for the swatch’s current colors, one for against white, and one for against black. + +
      + {getData('colors').map((color) => { + if ((color.name !== "white") && (color.name !== "gray") && (color.name !== "gray-dark")) { + return ( +
      +
      + ${color.name} + {color.hex} +
      + + {getSequence(100, 900, 100).map((value) => { + return ( +
      ${color.name}-{value}
      + ) + })} +
      + ) + } + })} + +
      +
      $gray-500#adb5bd
      + {getData('grays').map((gray) => { + return ( +
      $gray-{gray.name}
      + ) + })} +
      + +
      +
      + $black + #000 +
      +
      + $white + #fff +
      +
      +
      + +### Notes on Sass + +Sass cannot programmatically generate variables, so we manually created variables for every tint and shade ourselves. We specify the midpoint value (e.g., `$blue-500`) and use custom color functions to tint (lighten) or shade (darken) our colors via Sass’s `mix()` color function. + +Using `mix()` is not the same as `lighten()` and `darken()`—the former blends the specified color with white or black, while the latter only adjusts the lightness value of each color. The result is a much more complete suite of colors, as [shown in this CodePen demo](https://codepen.io/emdeoh/pen/zYOQOPB). + +Our `tint-color()` and `shade-color()` functions use `mix()` alongside our `$theme-color-interval` variable, which specifies a stepped percentage value for each mixed color we produce. See the `scss/_functions.scss` and `scss/_variables.scss` files for the full source code. + +## Color Sass maps + +Bootstrap’s source Sass files include three maps to help you quickly and easily loop over a list of colors and their hex values. + +- `$colors` lists all our available base (`500`) colors +- `$theme-colors` lists all semantically named theme colors (shown below) +- `$grays` lists all tints and shades of gray + +Within `scss/_variables.scss`, you’ll find Bootstrap’s color variables and Sass map. Here’s an example of the `$colors` Sass map: + + + +Add, remove, or modify values within the map to update how they’re used in many other components. Unfortunately at this time, not _every_ component utilizes this Sass map. Future updates will strive to improve upon this. Until then, plan on making use of the `${color}` variables and this Sass map. + +### Example + +Here’s how you can use these in your Sass: + +```scss +.alpha { color: $purple; } +.beta { + color: $yellow-300; + background-color: $indigo-900; +} +``` + +[Color]([[docsref:/utilities/colors]]) and [background]([[docsref:/utilities/background]]) utility classes are also available for setting `color` and `background-color` using the `500` color values. + +## Generating utilities + + + +Bootstrap doesn’t include `color` and `background-color` utilities for every color variable, but you can generate these yourself with our [utility API]([[docsref:/utilities/api]]) and our extended Sass maps added in v5.1.0. + +1. To start, make sure you’ve imported our functions, variables, mixins, and utilities. +2. Use our `map-merge-multiple()` function to quickly merge multiple Sass maps together in a new map. +3. Merge this new combined map to extend any utility with a `{color}-{level}` class name. + +Here’s an example that generates text color utilities (e.g., `.text-purple-500`) using the above steps. + +```scss +@import "bootstrap/scss/functions"; +@import "bootstrap/scss/variables"; +@import "bootstrap/scss/variables-dark"; +@import "bootstrap/scss/maps"; +@import "bootstrap/scss/mixins"; +@import "bootstrap/scss/utilities"; + +$all-colors: map-merge-multiple($blues, $indigos, $purples, $pinks, $reds, $oranges, $yellows, $greens, $teals, $cyans); + +$utilities: map-merge( + $utilities, + ( + "color": map-merge( + map-get($utilities, "color"), + ( + values: map-merge( + map-get(map-get($utilities, "color"), "values"), + ( + $all-colors + ), + ), + ), + ), + ) +); + +@import "bootstrap/scss/utilities/api"; +``` + +This will generate new `.text-{color}-{level}` utilities for every color and level. You can do the same for any other utility and property as well. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/components.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/components.mdx new file mode 100644 index 000000000..2aa7e8554 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/components.mdx @@ -0,0 +1,75 @@ +--- +title: Components +description: Learn how and why we build nearly all our components responsively and with base and modifier classes. +toc: true +--- + +## Base classes + +Bootstrap’s components are largely built with a base-modifier nomenclature. We group as many shared properties as possible into a base class, like `.btn`, and then group individual styles for each variant into modifier classes, like `.btn-primary` or `.btn-success`. + +To build our modifier classes, we use Sass’s `@each` loops to iterate over a Sass map. This is especially helpful for generating variants of a component by our `$theme-colors` and creating responsive variants for each breakpoint. As you customize these Sass maps and recompile, you’ll automatically see your changes reflected in these loops. + +Check out [our Sass maps and loops docs]([[docsref:/customize/sass#maps-and-loops]]) for how to customize these loops and extend Bootstrap’s base-modifier approach to your own code. + +## Modifiers + +Many of Bootstrap’s components are built with a base-modifier class approach. This means the bulk of the styling is contained to a base class (e.g., `.btn`) while style variations are confined to modifier classes (e.g., `.btn-danger`). These modifier classes are built from the `$theme-colors` map to make customizing the number and name of our modifier classes. + +Here are two examples of how we loop over the `$theme-colors` map to generate modifiers to the `.alert` and `.list-group` components. + + + + + +## Responsive + +These Sass loops aren’t limited to color maps, either. You can also generate responsive variations of your components. Take for example our responsive alignment of the dropdowns where we mix an `@each` loop for the `$grid-breakpoints` Sass map with a media query include. + + + +Should you modify your `$grid-breakpoints`, your changes will apply to all the loops iterating over that map. + + + +For more information and examples on how to modify our Sass maps and variables, please refer to [the CSS section of the Grid documentation]([[docsref:/layout/grid#css]]). + +## Creating your own + +We encourage you to adopt these guidelines when building with Bootstrap to create your own components. We’ve extended this approach ourselves to the custom components in our documentation and examples. Components like our callouts are built just like our provided components with base and modifier classes. + +
      +
      + This is a callout. We built it custom for our docs so our messages to you stand out. It has three variants via modifier classes. +
      +
      + +```html +
      ...
      +``` + +In your CSS, you’d have something like the following where the bulk of the styling is done via `.callout`. Then, the unique styles between each variant is controlled via modifier class. + +```scss +// Base class +.callout {} + +// Modifier classes +.callout-info {} +.callout-warning {} +.callout-danger {} +``` + +For the callouts, that unique styling is just a `border-left-color`. When you combine that base class with one of those modifier classes, you get your complete component family: + + +**This is an info callout.** Example text to show it in action. + + + +**This is a warning callout.** Example text to show it in action. + + + +**This is a danger callout.** Example text to show it in action. + diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/css-variables.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/css-variables.mdx new file mode 100644 index 000000000..20a0b9d44 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/css-variables.mdx @@ -0,0 +1,70 @@ +--- +title: CSS variables +description: Use Bootstrap’s CSS custom properties for fast and forward-looking design and development. +toc: true +--- + +Bootstrap includes many [CSS custom properties (variables)](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) in its compiled CSS for real-time customization without the need to recompile Sass. These provide easy access to commonly used values like our theme colors, breakpoints, and primary font stacks when working in your browser’s inspector, a code sandbox, or general prototyping. + +**All our custom properties are prefixed with `bs-`** to avoid conflicts with third party CSS. + +## Root variables + +Here are the variables we include (note that the `:root` is required) that can be accessed anywhere Bootstrap’s CSS is loaded. They’re located in our `_root.scss` file and included in our compiled dist files. + +### Default + +These CSS variables are available everywhere, regardless of color mode. + + + +### Dark mode + +These variables are scoped to our built-in dark mode. + + + +## Component variables + +Bootstrap 5 is increasingly making use of custom properties as local variables for various components. This way we reduce our compiled CSS, ensure styles aren’t inherited in places like nested tables, and allow some basic restyling and extending of Bootstrap components after Sass compilation. + +Have a look at our table documentation for some [insight into how we’re using CSS variables]([[docsref:/content/tables#how-do-the-variants-and-accented-tables-work]]). Our [navbars also use CSS variables]([[docsref:/components/navbar#css]]) as of v5.2.0. We’re also using CSS variables across our grids—primarily for gutters the [new opt-in CSS grid]([[docsref:/layout/css-grid]])—with more component usage coming in the future. + +Whenever possible, we'll assign CSS variables at the base component level (e.g., `.navbar` for navbar and its sub-components). This reduces guessing on where and how to customize, and allows for easy modifications by our team in future updates. + +## Prefix + +Most CSS variables use a prefix to avoid collisions with your own codebase. This prefix is in addition to the `--` that’s required on every CSS variable. + +Customize the prefix via the `$prefix` Sass variable. By default, it’s set to `bs-` (note the trailing dash). + +## Examples + +CSS variables offer similar flexibility to Sass’s variables, but without the need for compilation before being served to the browser. For example, here we’re resetting our page’s font and link styles with CSS variables. + +```css +body { + font: 1rem/1.5 var(--bs-font-sans-serif); +} +a { + color: var(--bs-blue); +} +``` + +## Focus variables + + + +Bootstrap provides custom `:focus` styles using a combination of Sass and CSS variables that can be optionally added to specific components and elements. We do not yet globally override all `:focus` styles. + +In our Sass, we set default values that can be customized before compiling. + + + +Those variables are then reassigned to `:root` level CSS variables that can be customized in real-time, including with options for `x` and `y` offsets (which default to their fallback value of `0`). + + + +## Grid breakpoints + +While we include our grid breakpoints as CSS variables (except for `xs`), be aware that **CSS variables do not work in media queries**. This is by design in the CSS spec for variables, but may change in coming years with support for `env()` variables. Check out [this Stack Overflow answer](https://stackoverflow.com/a/47212942) for some helpful links. In the meantime, you can use these variables in other CSS situations, as well as in your JavaScript. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/optimize.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/optimize.mdx new file mode 100644 index 000000000..0384ca050 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/optimize.mdx @@ -0,0 +1,88 @@ +--- +title: Optimize +description: Keep your projects lean, responsive, and maintainable so you can deliver the best experience and focus on more important jobs. +toc: true +--- + +## Lean Sass imports + +When using Sass in your asset pipeline, make sure you optimize Bootstrap by only `@import`ing the components you need. Your largest optimizations will likely come from the `Layout & Components` section of our `bootstrap.scss`. + + + + +If you’re not using a component, comment it out or delete it entirely. For example, if you’re not using the carousel, remove that import to save some file size in your compiled CSS. Keep in mind there are some dependencies across Sass imports that may make it more difficult to omit a file. + +## Lean JavaScript + +Bootstrap’s JavaScript includes every component in our primary dist files (`bootstrap.js` and `bootstrap.min.js`), and even our primary dependency (Popper) with our bundle files (`bootstrap.bundle.js` and `bootstrap.bundle.min.js`). While you’re customizing via Sass, be sure to remove related JavaScript. + +For instance, assuming you’re using your own JavaScript bundler like Webpack, Parcel, or Vite, you’d only import the JavaScript you plan on using. In the example below, we show how to just include our modal JavaScript: + +```js +// Import just what we need + +// import 'bootstrap/js/dist/alert'; +// import 'bootstrap/js/dist/button'; +// import 'bootstrap/js/dist/carousel'; +// import 'bootstrap/js/dist/collapse'; +// import 'bootstrap/js/dist/dropdown'; +import 'bootstrap/js/dist/modal'; +// import 'bootstrap/js/dist/offcanvas'; +// import 'bootstrap/js/dist/popover'; +// import 'bootstrap/js/dist/scrollspy'; +// import 'bootstrap/js/dist/tab'; +// import 'bootstrap/js/dist/toast'; +// import 'bootstrap/js/dist/tooltip'; +``` + +This way, you’re not including any JavaScript you don’t intend to use for components like buttons, carousels, and tooltips. If you’re importing dropdowns, tooltips or popovers, be sure to list the Popper dependency in your `package.json` file. + + +**Heads up!** Files in `bootstrap/js/dist` use the **default export**. To use them, do the following: + +```js +import Modal from 'bootstrap/js/dist/modal' +const modal = new Modal(document.getElementById('myModal')) +``` + + +## Autoprefixer .browserslistrc + +Bootstrap depends on Autoprefixer to automatically add browser prefixes to certain CSS properties. Prefixes are dictated by our `.browserslistrc` file, found in the root of the Bootstrap repo. Customizing this list of browsers and recompiling the Sass will automatically remove some CSS from your compiled CSS, if there are vendor prefixes unique to that browser or version. + +## Unused CSS + +_Help wanted with this section, please consider opening a PR. Thanks!_ + +While we don’t have a prebuilt example for using [PurgeCSS](https://github.com/FullHuman/purgecss) with Bootstrap, there are some helpful articles and walkthroughs that the community has written. Here are some options: + +- https://medium.com/dwarves-foundation/remove-unused-css-styles-from-bootstrap-using-purgecss-88395a2c5772 +- https://lukelowrey.com/automatically-removeunused-css-from-bootstrap-or-other-frameworks/ + +Lastly, this [CSS Tricks article on unused CSS](https://css-tricks.com/how-do-you-remove-unused-css-from-a-site/) shows how to use PurgeCSS and other similar tools. + +## Minify and gzip + +Whenever possible, be sure to compress all the code you serve to your visitors. If you’re using Bootstrap dist files, try to stick to the minified versions (indicated by the `.min.css` and `.min.js` extensions). If you’re building Bootstrap from the source with your own build system, be sure to implement your own minifiers for HTML, CSS, and JS. + +## Non-blocking files + +While minifying and using compression might seem like enough, making your files non-blocking ones is also a big step in making your site well-optimized and fast enough. + +If you are using a [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/) plugin in Google Chrome, you may have stumbled over FCP. [The First Contentful Paint](https://web.dev/articles/fcp) metric measures the time from when the page starts loading to when any part of the page’s content is rendered on the screen. + +You can improve FCP by deferring non-critical JavaScript or CSS. What does that mean? Simply, JavaScript or stylesheets that don’t need to be present on the first paint of your page should be marked with `async` or `defer` attributes. + +This ensures that the less important resources are loaded later and not blocking the first paint. On the other hand, critical resources can be included as inline scripts or styles. + +If you want to learn more about this, there are already a lot of great articles about it: + +- https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources/ +- https://web.dev/articles/defer-non-critical-css + +## Always use HTTPS + +Your website should only be available over HTTPS connections in production. HTTPS improves the security, privacy, and availability of all sites, and [there is no such thing as non-sensitive web traffic](https://https.cio.gov/everything/). The steps to configure your website to be served exclusively over HTTPS vary widely depending on your architecture and web hosting provider, and thus are beyond the scope of these docs. + +Sites served over HTTPS should also access all stylesheets, scripts, and other assets over HTTPS connections. Otherwise, you’ll be sending users [mixed active content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content), leading to potential vulnerabilities where a site can be compromised by altering a dependency. This can lead to security issues and in-browser warnings displayed to users. Whether you’re getting Bootstrap from a CDN or serving it yourself, ensure that you only access it over HTTPS connections. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/options.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/options.mdx new file mode 100644 index 000000000..926ae0312 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/options.mdx @@ -0,0 +1,31 @@ +--- +title: Options +description: Quickly customize Bootstrap with built-in variables to easily toggle global CSS preferences for controlling style and behavior. +--- + +Customize Bootstrap with our built-in custom variables file and easily toggle global CSS preferences with new `$enable-*` Sass variables. Override a variable’s value and recompile with `npm run test` as needed. + +You can find and customize these variables for key global options in Bootstrap’s `scss/_variables.scss` file. + + +| Variable | Values | Description | +| ------------------------------ | ---------------------------------- | -------------------------------------------------------------------------------------- | +| `$spacer` | `1rem` (default), or any value > 0 | Specifies the default spacer value to programmatically generate our [spacer utilities]([[docsref:/utilities/spacing]]). | +| `$enable-dark-mode` | `true` (default) or `false` | Enables built-in [dark mode support]([[docsref:/customize/color-modes#dark-mode]]) across the project and its components. | +| `$enable-rounded` | `true` (default) or `false` | Enables predefined `border-radius` styles on various components. | +| `$enable-shadows` | `true` or `false` (default) | Enables predefined decorative `box-shadow` styles on various components. Does not affect `box-shadow`s used for focus states. | +| `$enable-gradients` | `true` or `false` (default) | Enables predefined gradients via `background-image` styles on various components. | +| `$enable-transitions` | `true` (default) or `false` | Enables predefined `transition`s on various components. | +| `$enable-reduced-motion` | `true` (default) or `false` | Enables the [`prefers-reduced-motion` media query]([[docsref:/getting-started/accessibility#reduced-motion]]), which suppresses certain animations/transitions based on the users’ browser/operating system preferences. | +| `$enable-grid-classes` | `true` (default) or `false` | Enables the generation of CSS classes for the grid system (e.g. `.row`, `.col-md-1`, etc.). | +| `$enable-cssgrid` | `true` or `false` (default) | Enables the experimental CSS Grid system (e.g. `.grid`, `.g-col-md-1`, etc.). | +| `$enable-container-classes` | `true` (default) or `false` | Enables the generation of CSS classes for layout containers. (New in v5.2.0) | +| `$enable-caret` | `true` (default) or `false` | Enables pseudo element caret on `.dropdown-toggle`. | +| `$enable-button-pointers` | `true` (default) or `false` | Add “hand” cursor to non-disabled button elements. | +| `$enable-rfs` | `true` (default) or `false` | Globally enables [RFS]([[docsref:/getting-started/rfs]]). | +| `$enable-validation-icons` | `true` (default) or `false` | Enables `background-image` icons within textual inputs and some custom forms for validation states. | +| `$enable-negative-margins` | `true` or `false` (default) | Enables the generation of [negative margin utilities]([[docsref:/utilities/spacing#negative-margin]]). | +| `$enable-deprecation-messages` | `true` (default) or `false` | Set to `false` to hide warnings when using any of the deprecated mixins and functions that are planned to be removed in `v6`. | +| `$enable-important-utilities` | `true` (default) or `false` | Enables the `!important` suffix in utility classes. | +| `$enable-smooth-scroll` | `true` (default) or `false` | Applies `scroll-behavior: smooth` globally, except for users asking for reduced motion through [`prefers-reduced-motion` media query]([[docsref:/getting-started/accessibility#reduced-motion]]) | + diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/overview.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/overview.mdx new file mode 100644 index 000000000..7acb624ea --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/overview.mdx @@ -0,0 +1,51 @@ +--- +title: Customize +description: Learn how to theme, customize, and extend Bootstrap with Sass, a boatload of global options, an expansive color system, and more. +toc: false +aliases: "/docs/[[config:docs_version]]/customize/" +sections: + - title: Sass + description: Utilize our source Sass files to take advantage of variables, maps, mixins, and functions. + - title: Options + description: Customize Bootstrap with built-in variables to easily toggle global CSS preferences. + - title: Color + description: Learn about and customize the color systems that support the entire toolkit. + - title: Color modes + description: Explore our default light mode and the new dark mode, or create custom color modes yourself. + - title: Components + description: Learn how we build nearly all our components responsively and with base and modifier classes. + - title: CSS variables + description: Use Bootstrap’s CSS custom properties for fast and forward-looking design and development. + - title: Optimize + description: Keep your projects lean, responsive, and maintainable so you can deliver the best experience. +--- + +## Overview + +There are multiple ways to customize Bootstrap. Your best path can depend on your project, the complexity of your build tools, the version of Bootstrap you’re using, browser support, and more. + +Our two preferred methods are: + +1. Using Bootstrap [via package manager]([[docsref:/getting-started/download#package-managers]]) so you can use and extend our source files. +2. Using Bootstrap’s compiled distribution files or [jsDelivr]([[docsref:/getting-started/download#cdn-via-jsdelivr]]) so you can add onto or override Bootstrap’s styles. + +While we cannot go into details here on how to use every package manager, we can give some guidance on [using Bootstrap with your own Sass compiler]([[docsref:/customize/sass]]). + +For those who want to use the distribution files, review the [getting started page]([[docsref:/getting-started/introduction]]) for how to include those files and an example HTML page. From there, consult the docs for the layout, components, and behaviors you’d like to use. + +As you familiarize yourself with Bootstrap, continue exploring this section for more details on how to utilize our global options, making use of and changing our color system, how we build our components, how to use our growing list of CSS custom properties, and how to optimize your code when building with Bootstrap. + +## CSPs and embedded SVGs + +Several Bootstrap components include embedded SVGs in our CSS to style components consistently and easily across browsers and devices. **For organizations with more strict CSP configurations**, we’ve documented all instances of our embedded SVGs (all of which are applied via `background-image`) so you can more thoroughly review your options. + +- [Accordion]([[docsref:/components/accordion]]) +- [Carousel controls]([[docsref:/components/carousel#with-controls]]) +- [Close button]([[docsref:/components/close-button]]) (used in alerts and modals) +- [Form checkboxes and radio buttons]([[docsref:/forms/checks-radios]]) +- [Form switches]([[docsref:/forms/checks-radios#switches]]) +- [Form validation icons]([[docsref:/forms/validation#server-side]]) +- [Navbar toggle buttons]([[docsref:/components/navbar#responsive-behaviors]]) +- [Select menus]([[docsref:/forms/select]]) + +Based on [community conversation](https://github.com/twbs/bootstrap/issues/25394), some options for addressing this in your own codebase include [replacing the URLs with locally hosted assets]([[docsref:/getting-started/webpack#extracting-svg-files]]), removing the images and using inline images (not possible in all components), and modifying your CSP. Our recommendation is to carefully review your own security policies and decide on the best path forward, if necessary. diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/customize/sass.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/sass.mdx new file mode 100644 index 000000000..6352de402 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/customize/sass.mdx @@ -0,0 +1,363 @@ +--- +title: Sass +description: Utilize our source Sass files to take advantage of variables, maps, mixins, and functions to help you build faster and customize your project. +toc: true +--- + +Utilize our source Sass files to take advantage of variables, maps, mixins, and more. + + +Sass deprecation warnings are shown when compiling source Sass files with the latest versions of Dart Sass. This does not prevent compilation or usage of Bootstrap. We’re [working on a long-term fix]([[config:repo]]/issues/40962), but in the meantime these deprecation notices can be ignored. + + +## File structure + +Whenever possible, avoid modifying Bootstrap’s core files. For Sass, that means creating your own stylesheet that imports Bootstrap so you can modify and extend it. Assuming you’re using a package manager like npm, you’ll have a file structure that looks like this: + +```text +your-project/ +├── scss/ +│ └── custom.scss +└── node_modules/ +│ └── bootstrap/ +│ ├── js/ +│ └── scss/ +└── index.html +``` + +If you’ve downloaded our source files and aren’t using a package manager, you’ll want to manually create something similar to that structure, keeping Bootstrap’s source files separate from your own. + +```text +your-project/ +├── scss/ +│ └── custom.scss +├── bootstrap/ +│ ├── js/ +│ └── scss/ +└── index.html +``` + +## Importing + +In your `custom.scss`, you’ll import Bootstrap’s source Sass files. You have two options: include all of Bootstrap, or pick the parts you need. We encourage the latter, though be aware there are some requirements and dependencies across our components. You also will need to include some JavaScript for our plugins. + +```scss +// Custom.scss +// Option A: Include all of Bootstrap + +// Include any default variable overrides here (though functions won’t be available) + +@import "../node_modules/bootstrap/scss/bootstrap"; + +// Then add additional custom code here +``` + +```scss +// Custom.scss +// Option B: Include parts of Bootstrap + +// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc) +@import "../node_modules/bootstrap/scss/functions"; + +// 2. Include any default variable overrides here + +// 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets) +@import "../node_modules/bootstrap/scss/variables"; +@import "../node_modules/bootstrap/scss/variables-dark"; + +// 4. Include any default map overrides here + +// 5. Include remainder of required parts +@import "../node_modules/bootstrap/scss/maps"; +@import "../node_modules/bootstrap/scss/mixins"; +@import "../node_modules/bootstrap/scss/root"; + +// 6. Include any other optional stylesheet partials as desired; list below is not inclusive of all available stylesheets +@import "../node_modules/bootstrap/scss/utilities"; +@import "../node_modules/bootstrap/scss/reboot"; +@import "../node_modules/bootstrap/scss/type"; +@import "../node_modules/bootstrap/scss/images"; +@import "../node_modules/bootstrap/scss/containers"; +@import "../node_modules/bootstrap/scss/grid"; +@import "../node_modules/bootstrap/scss/helpers"; +// ... + +// 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss` +@import "../node_modules/bootstrap/scss/utilities/api"; + +// 8. Add additional custom code here +``` + +With that setup in place, you can begin to modify any of the Sass variables and maps in your `custom.scss`. You can also start to add parts of Bootstrap under the `// Optional` section as needed. We suggest using the full import stack from our `bootstrap.scss` file as your starting point. + +## Compiling + +In order to use your custom Sass code as CSS in the browser, you need a Sass compiler. Sass ships as a CLI package, but you can also compile it with other build tools like [Gulp](https://gulpjs.com/) or [Webpack](https://webpack.js.org/), or with GUI applications. Some IDEs also have Sass compilers built in or as downloadable extensions. + +We like to use the CLI to compile our Sass, but you can use whichever method you prefer. From the command line, run the following: + +```sh +# Install Sass globally +npm install -g sass + +# Watch your custom Sass for changes and compile it to CSS +sass --watch ./scss/custom.scss ./css/custom.css +``` + +Learn more about your options at [sass-lang.com/install](https://sass-lang.com/install/) and [compiling with VS Code](https://code.visualstudio.com/docs/languages/css#_transpiling-sass-and-less-into-css). + + +**Using Bootstrap with another build tool?** Consider reading our guides for compiling with [Webpack]([[docsref:/getting-started/webpack]]), [Parcel]([[docsref:/getting-started/parcel]]), or [Vite]([[docsref:/getting-started/vite]]). We also have production-ready demos in [our examples repository on GitHub](https://github.com/twbs/examples). + + +## Including + +Once your CSS is compiled, you can include it in your HTML files. Inside your `index.html` you’ll want to include your compiled CSS file. Be sure to update the path to your compiled CSS file if you’ve changed it. + +```html + + + + + + Custom Bootstrap + + + +

      Hello, world!

      + + +``` + +## Variable defaults + +Every Sass variable in Bootstrap includes the `!default` flag allowing you to override the variable’s default value in your own Sass without modifying Bootstrap’s source code. Copy and paste variables as needed, modify their values, and remove the `!default` flag. If a variable has already been assigned, then it won’t be re-assigned by the default values in Bootstrap. + +You will find the complete list of Bootstrap’s variables in `scss/_variables.scss`. Some variables are set to `null`, these variables don’t output the property unless they are overridden in your configuration. + +Variable overrides must come after our functions are imported, but before the rest of the imports. + +Here’s an example that changes the `background-color` and `color` for the `` when importing and compiling Bootstrap via npm: + +```scss +// Required +@import "../node_modules/bootstrap/scss/functions"; + +// Default variable overrides +$body-bg: #000; +$body-color: #111; + +// Required +@import "../node_modules/bootstrap/scss/variables"; +@import "../node_modules/bootstrap/scss/variables-dark"; +@import "../node_modules/bootstrap/scss/maps"; +@import "../node_modules/bootstrap/scss/mixins"; +@import "../node_modules/bootstrap/scss/root"; + +// Optional Bootstrap components here +@import "../node_modules/bootstrap/scss/reboot"; +@import "../node_modules/bootstrap/scss/type"; +// etc +``` + +Repeat as necessary for any variable in Bootstrap, including the global options below. + + + +## Maps and loops + +Bootstrap includes a handful of Sass maps, key value pairs that make it easier to generate families of related CSS. We use Sass maps for our colors, grid breakpoints, and more. Just like Sass variables, all Sass maps include the `!default` flag and can be overridden and extended. + +Some of our Sass maps are merged into empty ones by default. This is done to allow easy expansion of a given Sass map, but comes at the cost of making _removing_ items from a map slightly more difficult. + +### Modify map + +All variables in the `$theme-colors` map are defined as standalone variables. To modify an existing color in our `$theme-colors` map, add the following to your custom Sass file: + +```scss +$primary: #0074d9; +$danger: #ff4136; +``` + +Later on, these variables are set in Bootstrap’s `$theme-colors` map: + +```scss +$theme-colors: ( + "primary": $primary, + "danger": $danger +); +``` + +### Add to map + +Add new colors to `$theme-colors`, or any other map, by creating a new Sass map with your custom values and merging it with the original map. In this case, we'll create a new `$custom-colors` map and merge it with `$theme-colors`. + +```scss +// Create your own map +$custom-colors: ( + "custom-color": #900 +); + +// Merge the maps +$theme-colors: map-merge($theme-colors, $custom-colors); +``` + +### Remove from map + +To remove colors from `$theme-colors`, or any other map, use `map-remove`. Be aware you must insert `$theme-colors` between our requirements just after its definition in `variables` and before its usage in `maps`: + +```scss +// Required +@import "../node_modules/bootstrap/scss/functions"; +@import "../node_modules/bootstrap/scss/variables"; +@import "../node_modules/bootstrap/scss/variables-dark"; + +$theme-colors: map-remove($theme-colors, "info", "light", "dark"); + +@import "../node_modules/bootstrap/scss/maps"; +@import "../node_modules/bootstrap/scss/mixins"; +@import "../node_modules/bootstrap/scss/root"; + +// Optional +@import "../node_modules/bootstrap/scss/reboot"; +@import "../node_modules/bootstrap/scss/type"; +// etc +``` + +## Required keys + +Bootstrap assumes the presence of some specific keys within Sass maps as we used and extend these ourselves. As you customize the included maps, you may encounter errors where a specific Sass map’s key is being used. + +For example, we use the `primary`, `success`, and `danger` keys from `$theme-colors` for links, buttons, and form states. Replacing the values of these keys should present no issues, but removing them may cause Sass compilation issues. In these instances, you’ll need to modify the Sass code that makes use of those values. + +## Functions + +### Colors + +Next to the [Sass maps]([[docsref:/customize/color#color-sass-maps]]) we have, theme colors can also be used as standalone variables, like `$primary`. + +```scss +.custom-element { + color: $gray-100; + background-color: $dark; +} +``` + +You can lighten or darken colors with Bootstrap’s `tint-color()` and `shade-color()` functions. These functions will mix colors with black or white, unlike Sass’ native `lighten()` and `darken()` functions which will change the lightness by a fixed amount, which often doesn’t lead to the desired effect. + +`shift-color()` combines these two functions by shading the color if the weight is positive and tinting the color if the weight is negative. + + + +In practice, you’d call the function and pass in the color and weight parameters. + +```scss +.custom-element { + color: tint-color($primary, 10%); +} + +.custom-element-2 { + color: shade-color($danger, 30%); +} + +.custom-element-3 { + color: shift-color($success, 40%); + background-color: shift-color($success, -60%); +} +``` + +### Color contrast + +In order to meet the [Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/TR/WCAG/) contrast requirements, authors **must** provide a minimum [text color contrast of 4.5:1](https://www.w3.org/TR/WCAG/#contrast-minimum) and a minimum [non-text color contrast of 3:1](https://www.w3.org/TR/WCAG/#non-text-contrast), with very few exceptions. + +To help with this, we included the `color-contrast` function in Bootstrap. It uses the [WCAG contrast ratio algorithm](https://www.w3.org/TR/WCAG/#dfn-contrast-ratio) for calculating contrast thresholds based on [relative luminance](https://www.w3.org/TR/WCAG/#dfn-relative-luminance) in an `sRGB` color space to automatically return a light (`#fff`), dark (`#212529`) or black (`#000`) contrast color based on the specified base color. This function is especially useful for mixins or loops where you’re generating multiple classes. + +For example, to generate color swatches from our `$theme-colors` map: + +```scss +@each $color, $value in $theme-colors { + .swatch-#{$color} { + color: color-contrast($value); + } +} +``` + +It can also be used for one-off contrast needs: + +```scss +.custom-element { + color: color-contrast(#000); // returns `color: #fff` +} +``` + +You can also specify a base color with our color map functions: + +```scss +.custom-element { + color: color-contrast($dark); // returns `color: #fff` +} +``` + +### Escape SVG + +We use the `escape-svg` function to escape the `<`, `>` and `#` characters for SVG background images. When using the `escape-svg` function, data URIs must be quoted. + +### Add and Subtract functions + +We use the `add` and `subtract` functions to wrap the CSS `calc` function. The primary purpose of these functions is to avoid errors when a “unitless” `0` value is passed into a `calc` expression. Expressions like `calc(10px - 0)` will return an error in all browsers, despite being mathematically correct. + +Example where the calc is valid: + +```scss +$border-radius: .25rem; +$border-width: 1px; + +.element { + // Output calc(.25rem - 1px) is valid + border-radius: calc($border-radius - $border-width); +} + +.element { + // Output the same calc(.25rem - 1px) as above + border-radius: subtract($border-radius, $border-width); +} +``` + +Example where the calc is invalid: + +```scss +$border-radius: .25rem; +$border-width: 0; + +.element { + // Output calc(.25rem - 0) is invalid + border-radius: calc($border-radius - $border-width); +} + +.element { + // Output .25rem + border-radius: subtract($border-radius, $border-width); +} +``` + +## Mixins + +Our `scss/mixins/` directory has a ton of mixins that power parts of Bootstrap and can also be used across your own project. + +### Color schemes + +A shorthand mixin for the `prefers-color-scheme` media query is available with support for `light` and `dark` color schemes. See [the color modes documentation]([[docsref:/customize/color-modes]]) for information on our color mode mixin. + + + +```scss +.custom-element { + @include color-scheme(light) { + // Insert light mode styles here + } + + @include color-scheme(dark) { + // Insert dark mode styles here + } +} +``` diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/docsref.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/docsref.mdx new file mode 100644 index 000000000..f6b303e87 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/docsref.mdx @@ -0,0 +1,45 @@ +--- +title: Docs reference +description: Examples of Bootstrap’s documentation-specific components and styles. +aliases: "/docsref/" +toc: true +robots: noindex,follow +--- + +## Buttons + + + + + +## Callouts + + + Default callout + + + + Warning callout + + + + Danger callout + + +## Code example + +```scss +.test { + --color: blue; +} +``` + +
      + The HTML abbreviation element. +
      + +This is a test.`} /> + + + + diff --git a/app/vendor/twbs/bootstrap/site/src/content/docs/extend/approach.mdx b/app/vendor/twbs/bootstrap/site/src/content/docs/extend/approach.mdx new file mode 100644 index 000000000..1be156e64 --- /dev/null +++ b/app/vendor/twbs/bootstrap/site/src/content/docs/extend/approach.mdx @@ -0,0 +1,84 @@ +--- +title: Approach +description: Learn about the guiding principles, strategies, and techniques used to build and maintain Bootstrap so you can more easily customize and extend it yourself. +aliases: + - "/docs/[[config:docs_version]]/extend/" +--- + +While the getting started pages provide an introductory tour of the project and what it offers, this document focuses on _why_ we do the things we do in Bootstrap. It explains our philosophy to building on the web so that others can learn from us, contribute with us, and help us improve. + +See something that doesn’t sound right, or perhaps could be done better? [Open an issue]([[config:repo]]/issues/new/choose)—we’d love to discuss it with you. + +## Summary + +We'll dive into each of these more throughout, but at a high level, here’s what guides our approach. + +- Components should be responsive and mobile-first +- Components should be built with a base class and extended via modifier classes +- Component states should obey a common z-index scale +- Whenever possible, prefer an HTML and CSS implementation over JavaScript +- Whenever possible, use utilities over custom styles +- Whenever possible, avoid enforcing strict HTML requirements (children selectors) + +## Responsive + +Bootstrap’s responsive styles are built to be responsive, an approach that’s often referred to as _mobile-first_. We use this term in our docs and largely agree with it, but at times it can be too broad. While not every component _must_ be entirely responsive in Bootstrap, this responsive approach is about reducing CSS overrides by pushing you to add styles as the viewport becomes larger. + +Across Bootstrap, you’ll see this most clearly in our media queries. In most cases, we use `min-width` queries that begin to apply at a specific breakpoint and carry up through the higher breakpoints. For example, a `.d-none` applies from `min-width: 0` to infinity. On the other hand, a `.d-md-none` applies from the medium breakpoint and up. + +At times we'll use `max-width` when a component’s inherent complexity requires it. At times, these overrides are functionally and mentally clearer to implement and support than rewriting core functionality from our components. We strive to limit this approach, but will use it from time to time. + +## Classes + +Aside from our Reboot, a cross-browser normalization stylesheet, all our styles aim to use classes as selectors. This means steering clear of type selectors (e.g., `input[type="text"]`) and extraneous parent classes (e.g., `.parent .child`) that make styles too specific to easily override. + +As such, components should be built with a base class that houses common, not-to-be overridden property-value pairs. For example, `.btn` and `.btn-primary`. We use `.btn` for all the common styles like `display`, `padding`, and `border-width`. We then use modifiers like `.btn-primary` to add the color, background-color, border-color, etc. + +Modifier classes should only be used when there are multiple properties or values to be changed across multiple variants. Modifiers are not always necessary, so be sure you’re actually saving lines of code and preventing unnecessary overrides when creating them. Good examples of modifiers are our theme color classes and size variants. + +## z-index scales + +There are two `z-index` scales in Bootstrap—elements within a component and overlay components. + +### Component elements + +- Some components in Bootstrap are built with overlapping elements to prevent double borders without modifying the `border` property. For example, button groups, input groups, and pagination. +- These components share a standard `z-index` scale of `0` through `3`. +- `0` is default (initial), `1` is `:hover`, `2` is `:active`/`.active`, and `3` is `:focus`. +- This approach matches our expectations of highest user priority. If an element is focused, it’s in view and at the user’s attention. Active elements are second highest because they indicate state. Hover is third highest because it indicates user intent, but nearly _anything_ can be hovered. + +### Overlay components + +Bootstrap includes several components that function as an overlay of some kind. This includes, in order of highest `z-index`, dropdowns, fixed and sticky navbars, modals, tooltips, and popovers. These components have their own `z-index` scale that begins at `1000`. This starting number was chosen arbitrarily and serves as a small buffer between our styles and your project’s custom styles. + +Each overlay component increases its `z-index` value slightly in such a way that common UI principles allow user focused or hovered elements to remain in view at all times. For example, a modal is document blocking (e.g., you cannot take any other action save for the modal’s action), so we put that above our navbars. + +Learn more about this in our [`z-index` layout page]([[docsref:/layout/z-index]]). + +## HTML and CSS over JS + +Whenever possible, we prefer to write HTML and CSS over JavaScript. In general, HTML and CSS are more prolific and accessible to more people of all different experience levels. HTML and CSS are also faster in your browser than JavaScript, and your browser generally provides a great deal of functionality for you. + +This principle is our first-class JavaScript API using `data` attributes. You don’t need to write nearly any JavaScript to use our JavaScript plugins; instead, write HTML. Read more about this in [our JavaScript overview page]([[docsref:/getting-started/javascript#data-attributes]]). + +Lastly, our styles build on the fundamental behaviors of common web elements. Whenever possible, we prefer to use what the browser provides. For example, you can put a `.btn` class on nearly any element, but most elements don’t provide any semantic value or browser functionality. So instead, we use ` + + `} /> + +## File input + + + + + +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      `} /> + +## Color + +Set the `type="color"` and add `.form-control-color` to the ``. We use the modifier class to set fixed `height`s and override some inconsistencies between browsers. + +Color picker +`} /> + +## Datalists + +Datalists allow you to create a group of `