composer local test update

This commit is contained in:
Clemens Schwaighofer
2023-09-15 18:23:25 +09:00
parent 74c8b8d71e
commit c8aee19deb
234 changed files with 4549 additions and 2798 deletions

216
composer.lock generated
View File

@@ -80,16 +80,16 @@
},
{
"name": "composer/semver",
"version": "3.3.2",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": ""
},
"require": {
@@ -139,9 +139,9 @@
"versioning"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2"
"source": "https://github.com/composer/semver/tree/3.4.0"
},
"funding": [
{
@@ -157,7 +157,7 @@
"type": "tidelift"
}
],
"time": "2022-04-01T19:23:25+00:00"
"time": "2023-08-31T09:50:34+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -227,25 +227,29 @@
},
{
"name": "doctrine/deprecations",
"version": "v1.1.0",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "8cffffb2218e01f3b370bf763e00e81697725259"
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/8cffffb2218e01f3b370bf763e00e81697725259",
"reference": "8cffffb2218e01f3b370bf763e00e81697725259",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3"
"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"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
@@ -264,9 +268,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.1.0"
"source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
},
"time": "2023-05-29T18:55:17+00:00"
"time": "2023-06-03T09:27:29+00:00"
},
{
"name": "doctrine/instantiator",
@@ -540,16 +544,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.15.5",
"version": "v4.17.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e"
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": ""
},
"require": {
@@ -590,9 +594,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
},
"time": "2023-05-19T20:20:00+00:00"
"time": "2023-08-13T19:53:39+00:00"
},
{
"name": "phan/phan",
@@ -896,16 +900,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.7.2",
"version": "1.7.3",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d"
"reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"shasum": ""
},
"require": {
@@ -948,28 +952,29 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3"
},
"time": "2023-05-30T18:13:47+00:00"
"time": "2023-08-12T11:01:26+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.21.3",
"version": "1.24.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "b0c366dd2cea79407d635839d25423ba07c55dd6"
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b0c366dd2cea79407d635839d25423ba07c55dd6",
"reference": "b0c366dd2cea79407d635839d25423ba07c55dd6",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/annotations": "^2.0",
"nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
@@ -994,22 +999,22 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.21.3"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0"
},
"time": "2023-05-29T19:31:28+00:00"
"time": "2023-09-07T20:46:32+00:00"
},
{
"name": "phpstan/phpstan",
"version": "1.10.15",
"version": "1.10.34",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd"
"reference": "7f806b6f1403e6914c778140e2ba07c293cb4901"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd",
"reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/7f806b6f1403e6914c778140e2ba07c293cb4901",
"reference": "7f806b6f1403e6914c778140e2ba07c293cb4901",
"shasum": ""
},
"require": {
@@ -1058,20 +1063,20 @@
"type": "tidelift"
}
],
"time": "2023-05-09T15:28:01+00:00"
"time": "2023-09-13T09:49:47+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.26",
"version": "9.2.28",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
"reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
"reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
"shasum": ""
},
"require": {
@@ -1127,7 +1132,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.28"
},
"funding": [
{
@@ -1135,7 +1141,7 @@
"type": "github"
}
],
"time": "2023-03-06T12:58:08+00:00"
"time": "2023-09-12T14:36:20+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1380,16 +1386,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.8",
"version": "9.6.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e"
"reference": "a122c2ebd469b751d774aa0f613dc0d67697653f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a122c2ebd469b751d774aa0f613dc0d67697653f",
"reference": "a122c2ebd469b751d774aa0f613dc0d67697653f",
"shasum": ""
},
"require": {
@@ -1404,7 +1410,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=7.3",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-code-coverage": "^9.2.28",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",
@@ -1463,7 +1469,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.8"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.12"
},
"funding": [
{
@@ -1479,7 +1485,7 @@
"type": "tidelift"
}
],
"time": "2023-05-11T05:14:45+00:00"
"time": "2023-09-12T14:39:31+00:00"
},
{
"name": "psr/container",
@@ -2156,16 +2162,16 @@
},
{
"name": "sebastian/global-state",
"version": "5.0.5",
"version": "5.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
"reference": "bde739e7565280bda77be70044ac1047bc007e34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
"reference": "bde739e7565280bda77be70044ac1047bc007e34",
"shasum": ""
},
"require": {
@@ -2208,7 +2214,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
},
"funding": [
{
@@ -2216,7 +2222,7 @@
"type": "github"
}
],
"time": "2022-02-14T08:28:10+00:00"
"time": "2023-08-02T09:26:13+00:00"
},
{
"name": "sebastian/lines-of-code",
@@ -2616,16 +2622,16 @@
},
{
"name": "symfony/console",
"version": "v6.3.0",
"version": "v6.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7"
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
"shasum": ""
},
"require": {
@@ -2686,7 +2692,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.3.0"
"source": "https://github.com/symfony/console/tree/v6.3.4"
},
"funding": [
{
@@ -2702,7 +2708,7 @@
"type": "tidelift"
}
],
"time": "2023-05-29T12:49:39+00:00"
"time": "2023-08-16T10:10:12+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -2773,16 +2779,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@@ -2797,7 +2803,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2835,7 +2841,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@@ -2851,20 +2857,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
"reference": "875e90aeea2777b6f135677f618529449334a612"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": ""
},
"require": {
@@ -2876,7 +2882,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2916,7 +2922,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
},
"funding": [
{
@@ -2932,20 +2938,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": ""
},
"require": {
@@ -2957,7 +2963,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3000,7 +3006,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
},
"funding": [
{
@@ -3016,20 +3022,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@@ -3044,7 +3050,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3083,7 +3089,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@@ -3099,20 +3105,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": ""
},
"require": {
@@ -3121,7 +3127,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3166,7 +3172,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
},
"funding": [
{
@@ -3182,7 +3188,7 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/service-contracts",
@@ -3268,16 +3274,16 @@
},
{
"name": "symfony/string",
"version": "v6.3.0",
"version": "v6.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f"
"reference": "53d1a83225002635bca3482fcbf963001313fb68"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
"url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68",
"reference": "53d1a83225002635bca3482fcbf963001313fb68",
"shasum": ""
},
"require": {
@@ -3334,7 +3340,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.3.0"
"source": "https://github.com/symfony/string/tree/v6.3.2"
},
"funding": [
{
@@ -3350,7 +3356,7 @@
"type": "tidelift"
}
],
"time": "2023-03-21T21:06:29+00:00"
"time": "2023-07-05T08:41:27+00:00"
},
{
"name": "theseer/tokenizer",

View File

@@ -60,6 +60,7 @@ return array(
'PHPUnit\\Framework\\Constraint\\LogicalXor' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php',
'PHPUnit\\Framework\\Constraint\\ObjectEquals' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasProperty' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasProperty.php',
'PHPUnit\\Framework\\Constraint\\Operator' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php',
'PHPUnit\\Framework\\Constraint\\RegularExpression' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php',
'PHPUnit\\Framework\\Constraint\\SameSize' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php',
@@ -290,8 +291,8 @@ return array(
'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistDirectoriesToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistIncludesToCoverage' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistIncludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php',
'PHPUnit\\TextUI\\XmlConfiguration\\Php' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PhpHandler' => $vendorDir . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php',

View File

@@ -248,6 +248,7 @@ class ComposerStaticInitdd705c6e8ab22e0d642372dec7767718
'PHPUnit\\Framework\\Constraint\\LogicalXor' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php',
'PHPUnit\\Framework\\Constraint\\ObjectEquals' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php',
'PHPUnit\\Framework\\Constraint\\ObjectHasProperty' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasProperty.php',
'PHPUnit\\Framework\\Constraint\\Operator' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php',
'PHPUnit\\Framework\\Constraint\\RegularExpression' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php',
'PHPUnit\\Framework\\Constraint\\SameSize' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php',
@@ -478,8 +479,8 @@ class ComposerStaticInitdd705c6e8ab22e0d642372dec7767718
'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistDirectoriesToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistIncludesToCoverage' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistIncludesToCoverage.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php',
'PHPUnit\\TextUI\\XmlConfiguration\\Php' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php',
'PHPUnit\\TextUI\\XmlConfiguration\\PhpHandler' => __DIR__ . '/..' . '/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php',

View File

@@ -76,17 +76,17 @@
},
{
"name": "composer/semver",
"version": "3.3.2",
"version_normalized": "3.3.2.0",
"version": "3.4.0",
"version_normalized": "3.4.0.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": ""
},
"require": {
@@ -96,7 +96,7 @@
"phpstan/phpstan": "^1.4",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"time": "2022-04-01T19:23:25+00:00",
"time": "2023-08-31T09:50:34+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -138,9 +138,9 @@
"versioning"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2"
"source": "https://github.com/composer/semver/tree/3.4.0"
},
"funding": [
{
@@ -229,31 +229,35 @@
},
{
"name": "doctrine/deprecations",
"version": "v1.1.0",
"version_normalized": "1.1.0.0",
"version": "v1.1.1",
"version_normalized": "1.1.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "8cffffb2218e01f3b370bf763e00e81697725259"
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/8cffffb2218e01f3b370bf763e00e81697725259",
"reference": "8cffffb2218e01f3b370bf763e00e81697725259",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3"
"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"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"time": "2023-05-29T18:55:17+00:00",
"time": "2023-06-03T09:27:29+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -269,7 +273,7 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.1.0"
"source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
},
"install-path": "../doctrine/deprecations"
},
@@ -560,17 +564,17 @@
},
{
"name": "nikic/php-parser",
"version": "v4.15.5",
"version_normalized": "4.15.5.0",
"version": "v4.17.1",
"version_normalized": "4.17.1.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e"
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e",
"reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": ""
},
"require": {
@@ -581,7 +585,7 @@
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
},
"time": "2023-05-19T20:20:00+00:00",
"time": "2023-08-13T19:53:39+00:00",
"bin": [
"bin/php-parse"
],
@@ -613,7 +617,7 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
},
"install-path": "../nikic/php-parser"
},
@@ -934,17 +938,17 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.7.2",
"version_normalized": "1.7.2.0",
"version": "1.7.3",
"version_normalized": "1.7.3.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d"
"reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419",
"shasum": ""
},
"require": {
@@ -963,7 +967,7 @@
"rector/rector": "^0.13.9",
"vimeo/psalm": "^4.25"
},
"time": "2023-05-30T18:13:47+00:00",
"time": "2023-08-12T11:01:26+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -989,29 +993,30 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3"
},
"install-path": "../phpdocumentor/type-resolver"
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.21.3",
"version_normalized": "1.21.3.0",
"version": "1.24.0",
"version_normalized": "1.24.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "b0c366dd2cea79407d635839d25423ba07c55dd6"
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b0c366dd2cea79407d635839d25423ba07c55dd6",
"reference": "b0c366dd2cea79407d635839d25423ba07c55dd6",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/annotations": "^2.0",
"nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
@@ -1021,7 +1026,7 @@
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.2"
},
"time": "2023-05-29T19:31:28+00:00",
"time": "2023-09-07T20:46:32+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -1038,23 +1043,23 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.21.3"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0"
},
"install-path": "../phpstan/phpdoc-parser"
},
{
"name": "phpstan/phpstan",
"version": "1.10.15",
"version_normalized": "1.10.15.0",
"version": "1.10.34",
"version_normalized": "1.10.34.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd"
"reference": "7f806b6f1403e6914c778140e2ba07c293cb4901"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd",
"reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/7f806b6f1403e6914c778140e2ba07c293cb4901",
"reference": "7f806b6f1403e6914c778140e2ba07c293cb4901",
"shasum": ""
},
"require": {
@@ -1063,7 +1068,7 @@
"conflict": {
"phpstan/phpstan-shim": "*"
},
"time": "2023-05-09T15:28:01+00:00",
"time": "2023-09-13T09:49:47+00:00",
"bin": [
"phpstan",
"phpstan.phar"
@@ -1109,17 +1114,17 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.26",
"version_normalized": "9.2.26.0",
"version": "9.2.28",
"version_normalized": "9.2.28.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
"reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
"reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
"shasum": ""
},
"require": {
@@ -1144,7 +1149,7 @@
"ext-pcov": "PHP extension that provides line coverage",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"time": "2023-03-06T12:58:08+00:00",
"time": "2023-09-12T14:36:20+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -1177,7 +1182,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.28"
},
"funding": [
{
@@ -1442,17 +1448,17 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.8",
"version_normalized": "9.6.8.0",
"version": "9.6.12",
"version_normalized": "9.6.12.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e"
"reference": "a122c2ebd469b751d774aa0f613dc0d67697653f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e",
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a122c2ebd469b751d774aa0f613dc0d67697653f",
"reference": "a122c2ebd469b751d774aa0f613dc0d67697653f",
"shasum": ""
},
"require": {
@@ -1467,7 +1473,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=7.3",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-code-coverage": "^9.2.28",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",
@@ -1488,7 +1494,7 @@
"ext-soap": "To be able to generate mocks based on WSDL files",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"time": "2023-05-11T05:14:45+00:00",
"time": "2023-09-12T14:39:31+00:00",
"bin": [
"phpunit"
],
@@ -1528,7 +1534,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.8"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.12"
},
"funding": [
{
@@ -2254,17 +2260,17 @@
},
{
"name": "sebastian/global-state",
"version": "5.0.5",
"version_normalized": "5.0.5.0",
"version": "5.0.6",
"version_normalized": "5.0.6.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
"reference": "bde739e7565280bda77be70044ac1047bc007e34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
"reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
"reference": "bde739e7565280bda77be70044ac1047bc007e34",
"shasum": ""
},
"require": {
@@ -2279,7 +2285,7 @@
"suggest": {
"ext-uopz": "*"
},
"time": "2022-02-14T08:28:10+00:00",
"time": "2023-08-02T09:26:13+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -2309,7 +2315,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
},
"funding": [
{
@@ -2738,17 +2744,17 @@
},
{
"name": "symfony/console",
"version": "v6.3.0",
"version_normalized": "6.3.0.0",
"version": "v6.3.4",
"version_normalized": "6.3.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7"
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
"shasum": ""
},
"require": {
@@ -2777,7 +2783,7 @@
"symfony/process": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0"
},
"time": "2023-05-29T12:49:39+00:00",
"time": "2023-08-16T10:10:12+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -2811,7 +2817,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.3.0"
"source": "https://github.com/symfony/console/tree/v6.3.4"
},
"funding": [
{
@@ -2901,17 +2907,17 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@@ -2923,11 +2929,11 @@
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2966,7 +2972,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@@ -2986,17 +2992,17 @@
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
"reference": "875e90aeea2777b6f135677f618529449334a612"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": ""
},
"require": {
@@ -3005,11 +3011,11 @@
"suggest": {
"ext-intl": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3050,7 +3056,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
},
"funding": [
{
@@ -3070,17 +3076,17 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": ""
},
"require": {
@@ -3089,11 +3095,11 @@
"suggest": {
"ext-intl": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3137,7 +3143,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
},
"funding": [
{
@@ -3157,17 +3163,17 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@@ -3179,11 +3185,11 @@
"suggest": {
"ext-mbstring": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-07-28T09:04:16+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3223,7 +3229,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@@ -3243,27 +3249,27 @@
},
{
"name": "symfony/polyfill-php80",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3309,7 +3315,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
},
"funding": [
{
@@ -3414,17 +3420,17 @@
},
{
"name": "symfony/string",
"version": "v6.3.0",
"version_normalized": "6.3.0.0",
"version": "v6.3.2",
"version_normalized": "6.3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f"
"reference": "53d1a83225002635bca3482fcbf963001313fb68"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
"url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68",
"reference": "53d1a83225002635bca3482fcbf963001313fb68",
"shasum": ""
},
"require": {
@@ -3444,7 +3450,7 @@
"symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^5.4|^6.0"
},
"time": "2023-03-21T21:06:29+00:00",
"time": "2023-07-05T08:41:27+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -3483,7 +3489,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.3.0"
"source": "https://github.com/symfony/string/tree/v6.3.2"
},
"funding": [
{

View File

@@ -3,7 +3,7 @@
'name' => '__root__',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '513b115d5729d1001743baf12d8991cc385b20d9',
'reference' => '74c8b8d71e6f3d439d5e98d4299924c367274ef4',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -13,7 +13,7 @@
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '513b115d5729d1001743baf12d8991cc385b20d9',
'reference' => '74c8b8d71e6f3d439d5e98d4299924c367274ef4',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -29,9 +29,9 @@
'dev_requirement' => true,
),
'composer/semver' => array(
'pretty_version' => '3.3.2',
'version' => '3.3.2.0',
'reference' => '3953f23262f2bff1919fc82183ad9acb13ff62c9',
'pretty_version' => '3.4.0',
'version' => '3.4.0.0',
'reference' => '35e8d0af4486141bc745f23a29cc2091eb624a32',
'type' => 'library',
'install_path' => __DIR__ . '/./semver',
'aliases' => array(),
@@ -47,9 +47,9 @@
'dev_requirement' => true,
),
'doctrine/deprecations' => array(
'pretty_version' => 'v1.1.0',
'version' => '1.1.0.0',
'reference' => '8cffffb2218e01f3b370bf763e00e81697725259',
'pretty_version' => 'v1.1.1',
'version' => '1.1.1.0',
'reference' => '612a3ee5ab0d5dd97b7cf3874a6efe24325efac3',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/deprecations',
'aliases' => array(),
@@ -101,9 +101,9 @@
'dev_requirement' => true,
),
'nikic/php-parser' => array(
'pretty_version' => 'v4.15.5',
'version' => '4.15.5.0',
'reference' => '11e2663a5bc9db5d714eedb4277ee300403b4a9e',
'pretty_version' => 'v4.17.1',
'version' => '4.17.1.0',
'reference' => 'a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d',
'type' => 'library',
'install_path' => __DIR__ . '/../nikic/php-parser',
'aliases' => array(),
@@ -155,36 +155,36 @@
'dev_requirement' => true,
),
'phpdocumentor/type-resolver' => array(
'pretty_version' => '1.7.2',
'version' => '1.7.2.0',
'reference' => 'b2fe4d22a5426f38e014855322200b97b5362c0d',
'pretty_version' => '1.7.3',
'version' => '1.7.3.0',
'reference' => '3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419',
'type' => 'library',
'install_path' => __DIR__ . '/../phpdocumentor/type-resolver',
'aliases' => array(),
'dev_requirement' => true,
),
'phpstan/phpdoc-parser' => array(
'pretty_version' => '1.21.3',
'version' => '1.21.3.0',
'reference' => 'b0c366dd2cea79407d635839d25423ba07c55dd6',
'pretty_version' => '1.24.0',
'version' => '1.24.0.0',
'reference' => '3510b0a6274cc42f7219367cb3abfc123ffa09d6',
'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpdoc-parser',
'aliases' => array(),
'dev_requirement' => true,
),
'phpstan/phpstan' => array(
'pretty_version' => '1.10.15',
'version' => '1.10.15.0',
'reference' => '762c4dac4da6f8756eebb80e528c3a47855da9bd',
'pretty_version' => '1.10.34',
'version' => '1.10.34.0',
'reference' => '7f806b6f1403e6914c778140e2ba07c293cb4901',
'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpstan',
'aliases' => array(),
'dev_requirement' => true,
),
'phpunit/php-code-coverage' => array(
'pretty_version' => '9.2.26',
'version' => '9.2.26.0',
'reference' => '443bc6912c9bd5b409254a40f4b0f4ced7c80ea1',
'pretty_version' => '9.2.28',
'version' => '9.2.28.0',
'reference' => '7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/php-code-coverage',
'aliases' => array(),
@@ -227,9 +227,9 @@
'dev_requirement' => true,
),
'phpunit/phpunit' => array(
'pretty_version' => '9.6.8',
'version' => '9.6.8.0',
'reference' => '17d621b3aff84d0c8b62539e269e87d8d5baa76e',
'pretty_version' => '9.6.12',
'version' => '9.6.12.0',
'reference' => 'a122c2ebd469b751d774aa0f613dc0d67697653f',
'type' => 'library',
'install_path' => __DIR__ . '/../phpunit/phpunit',
'aliases' => array(),
@@ -341,9 +341,9 @@
'dev_requirement' => true,
),
'sebastian/global-state' => array(
'pretty_version' => '5.0.5',
'version' => '5.0.5.0',
'reference' => '0ca8db5a5fc9c8646244e629625ac486fa286bf2',
'pretty_version' => '5.0.6',
'version' => '5.0.6.0',
'reference' => 'bde739e7565280bda77be70044ac1047bc007e34',
'type' => 'library',
'install_path' => __DIR__ . '/../sebastian/global-state',
'aliases' => array(),
@@ -413,9 +413,9 @@
'dev_requirement' => true,
),
'symfony/console' => array(
'pretty_version' => 'v6.3.0',
'version' => '6.3.0.0',
'reference' => '8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7',
'pretty_version' => 'v6.3.4',
'version' => '6.3.4.0',
'reference' => 'eca495f2ee845130855ddf1cf18460c38966c8b6',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
@@ -431,45 +431,45 @@
'dev_requirement' => true,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '5bbc823adecdae860bb64756d639ecfec17b050a',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '511a08c03c1960e08a883f4cffcacd219b758354',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '875e90aeea2777b6f135677f618529449334a612',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '19bd1e4fcd5b91116f14d8533c57831ed00571b6',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '42292d99c55abe617799667f454222c54c60e229',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
@@ -485,9 +485,9 @@
'dev_requirement' => true,
),
'symfony/string' => array(
'pretty_version' => 'v6.3.0',
'version' => '6.3.0.0',
'reference' => 'f2e190ee75ff0f5eced645ec0be5c66fac81f51f',
'pretty_version' => 'v6.3.2',
'version' => '6.3.2.0',
'reference' => '53d1a83225002635bca3482fcbf963001313fb68',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(),

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
### [3.4.0] 2023-08-31
* Support larger major version numbers (#149)
### [3.3.2] 2022-04-01
* Fixed handling of non-string values (#134)
@@ -175,6 +179,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
* Changed: code style using php-cs-fixer.
[3.4.0]: https://github.com/composer/semver/compare/3.3.2...3.4.0
[3.3.2]: https://github.com/composer/semver/compare/3.3.1...3.3.2
[3.3.1]: https://github.com/composer/semver/compare/3.3.0...3.3.1
[3.3.0]: https://github.com/composer/semver/compare/3.2.9...3.3.0

View File

@@ -6,8 +6,9 @@ Semver (Semantic Versioning) library that offers utilities, version constraint p
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
[![Continuous Integration](https://github.com/composer/semver/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/composer/semver/actions)
[![Continuous Integration](https://github.com/composer/semver/actions/workflows/continuous-integration.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/continuous-integration.yml)
[![PHP Lint](https://github.com/composer/semver/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/lint.yml)
[![PHPStan](https://github.com/composer/semver/actions/workflows/phpstan.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/phpstan.yml)
Installation
------------
@@ -15,7 +16,7 @@ Installation
Install the latest version with:
```bash
$ composer require composer/semver
composer require composer/semver
```

View File

@@ -27,7 +27,7 @@
}
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues"
},
"require": {

View File

@@ -0,0 +1,11 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$operator of class Composer\\\\Semver\\\\Constraint\\\\Constraint constructor expects '\\!\\='\\|'\\<'\\|'\\<\\='\\|'\\<\\>'\\|'\\='\\|'\\=\\='\\|'\\>'\\|'\\>\\=', non\\-falsy\\-string given\\.$#"
count: 1
path: src/VersionParser.php
-
message: "#^Strict comparison using \\=\\=\\= between null and non\\-empty\\-string will always evaluate to false\\.$#"
count: 2
path: src/VersionParser.php

View File

@@ -134,15 +134,15 @@ class VersionParser
}
// match classical versioning
if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
if (preg_match('{^v?(\d{1,5}+)(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = $matches[1]
. (!empty($matches[2]) ? $matches[2] : '.0')
. (!empty($matches[3]) ? $matches[3] : '.0')
. (!empty($matches[4]) ? $matches[4] : '.0');
$index = 5;
// match date(time) based versioning
} elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = preg_replace('{\D}', '.', $matches[1]);
} elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3}){0,2})' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = (string) preg_replace('{\D}', '.', $matches[1]);
$index = 2;
}
@@ -260,16 +260,16 @@ class VersionParser
}
$orGroups = array();
foreach ($orConstraints as $constraints) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
foreach ($orConstraints as $orConstraint) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
if (false === $andConstraints) {
throw new \RuntimeException('Failed to preg_split string: '.$constraints);
throw new \RuntimeException('Failed to preg_split string: '.$orConstraint);
}
if (\count($andConstraints) > 1) {
$constraintObjects = array();
foreach ($andConstraints as $constraint) {
foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
$constraintObjects[] = $parsedConstraint;
foreach ($andConstraints as $andConstraint) {
foreach ($this->parseConstraint($andConstraint) as $parsedAndConstraint) {
$constraintObjects[] = $parsedAndConstraint;
}
}
} else {
@@ -285,11 +285,11 @@ class VersionParser
$orGroups[] = $constraint;
}
$constraint = MultiConstraint::create($orGroups, false);
$parsedConstraint = MultiConstraint::create($orGroups, false);
$constraint->setPrettyString($prettyConstraint);
$parsedConstraint->setPrettyString($prettyConstraint);
return $constraint;
return $parsedConstraint;
}
/**

View File

@@ -1,22 +1,28 @@
{
"name": "doctrine/deprecations",
"type": "library",
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"license": "MIT",
"type": "library",
"homepage": "https://www.doctrine-project.org/",
"require": {
"php": "^7.1|^8.0"
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3",
"doctrine/coding-standard": "^9"
"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"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"autoload": {
"psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"}
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"autoload-dev": {
"psr-4": {

View File

@@ -8,6 +8,7 @@ use Psr\Log\LoggerInterface;
use function array_key_exists;
use function array_reduce;
use function assert;
use function debug_backtrace;
use function sprintf;
use function strpos;
@@ -46,7 +47,7 @@ class Deprecation
private const TYPE_TRIGGER_ERROR = 2;
private const TYPE_PSR_LOGGER = 4;
/** @var self::TYPE_*|null */
/** @var int-mask-of<self::TYPE_*>|null */
private static $type;
/** @var LoggerInterface|null */
@@ -56,6 +57,9 @@ class Deprecation
private static $ignoredPackages = [];
/** @var array<string,int> */
private static $triggeredDeprecations = [];
/** @var array<string,bool> */
private static $ignoredLinks = [];
/** @var bool */
@@ -68,7 +72,7 @@ class Deprecation
* deprecation. It is additionally used to de-duplicate the trigger of the
* same deprecation during a request.
*
* @param mixed $args
* @param float|int|string $args
*/
public static function trigger(string $package, string $link, string $message, ...$args): void
{
@@ -78,13 +82,17 @@ class Deprecation
return;
}
if (array_key_exists($link, self::$ignoredLinks)) {
self::$ignoredLinks[$link]++;
} else {
self::$ignoredLinks[$link] = 1;
if (isset(self::$ignoredLinks[$link])) {
return;
}
if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
if (array_key_exists($link, self::$triggeredDeprecations)) {
self::$triggeredDeprecations[$link]++;
} else {
self::$triggeredDeprecations[$link] = 1;
}
if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
return;
}
@@ -116,7 +124,7 @@ class Deprecation
* deprecation tracking is enabled even during deduplication, because it
* needs to call {@link debug_backtrace()}
*
* @param mixed $args
* @param float|int|string $args
*/
public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void
{
@@ -129,7 +137,7 @@ class Deprecation
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
// first check that the caller is not from a tests folder, in which case we always let deprecations pass
if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
if (isset($backtrace[1]['file'], $backtrace[0]['file']) && strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
$path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR;
if (strpos($backtrace[0]['file'], $path) === false) {
@@ -141,13 +149,17 @@ class Deprecation
}
}
if (array_key_exists($link, self::$ignoredLinks)) {
self::$ignoredLinks[$link]++;
} else {
self::$ignoredLinks[$link] = 1;
if (isset(self::$ignoredLinks[$link])) {
return;
}
if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
if (array_key_exists($link, self::$triggeredDeprecations)) {
self::$triggeredDeprecations[$link]++;
} else {
self::$triggeredDeprecations[$link] = 1;
}
if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
return;
}
@@ -161,7 +173,7 @@ class Deprecation
}
/**
* @param array<mixed> $backtrace
* @param list<array{function: string, line?: int, file?: string, class?: class-string, type?: string, args?: mixed[], object?: object}> $backtrace
*/
private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void
{
@@ -169,12 +181,14 @@ class Deprecation
if (($type & self::TYPE_PSR_LOGGER) > 0) {
$context = [
'file' => $backtrace[0]['file'],
'line' => $backtrace[0]['line'],
'file' => $backtrace[0]['file'] ?? null,
'line' => $backtrace[0]['line'] ?? null,
'package' => $package,
'link' => $link,
];
assert(self::$logger !== null);
self::$logger->notice($message, $context);
}
@@ -184,10 +198,10 @@ class Deprecation
$message .= sprintf(
' (%s:%d called by %s:%d, %s, package %s)',
self::basename($backtrace[0]['file']),
$backtrace[0]['line'],
self::basename($backtrace[1]['file']),
$backtrace[1]['line'],
self::basename($backtrace[0]['file'] ?? 'native code'),
$backtrace[0]['line'] ?? 0,
self::basename($backtrace[1]['file'] ?? 'native code'),
$backtrace[1]['line'] ?? 0,
$link,
$package
);
@@ -211,16 +225,19 @@ class Deprecation
public static function enableTrackingDeprecations(): void
{
self::$type = self::$type ?? 0;
self::$type |= self::TYPE_TRACK_DEPRECATIONS;
}
public static function enableWithTriggerError(): void
{
self::$type = self::$type ?? 0;
self::$type |= self::TYPE_TRIGGER_ERROR;
}
public static function enableWithPsrLogger(LoggerInterface $logger): void
{
self::$type = self::$type ?? 0;
self::$type |= self::TYPE_PSR_LOGGER;
self::$logger = $logger;
}
@@ -235,9 +252,10 @@ class Deprecation
self::$type = self::TYPE_NONE;
self::$logger = null;
self::$deduplication = true;
self::$ignoredLinks = [];
foreach (self::$ignoredLinks as $link => $count) {
self::$ignoredLinks[$link] = 0;
foreach (self::$triggeredDeprecations as $link => $count) {
self::$triggeredDeprecations[$link] = 0;
}
}
@@ -249,13 +267,13 @@ class Deprecation
public static function ignoreDeprecations(string ...$links): void
{
foreach ($links as $link) {
self::$ignoredLinks[$link] = 0;
self::$ignoredLinks[$link] = true;
}
}
public static function getUniqueTriggeredDeprecationsCount(): int
{
return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) {
return array_reduce(self::$triggeredDeprecations, static function (int $carry, int $count) {
return $carry + $count;
}, 0);
}
@@ -267,11 +285,11 @@ class Deprecation
*/
public static function getTriggeredDeprecations(): array
{
return self::$ignoredLinks;
return self::$triggeredDeprecations;
}
/**
* @return self::TYPE_*
* @return int-mask-of<self::TYPE_*>
*/
private static function getTypeFromEnv(): int
{

View File

@@ -0,0 +1,9 @@
parameters:
level: 6
paths:
- lib
- tests
includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon

30
vendor/doctrine/deprecations/psalm.xml vendored Normal file
View File

@@ -0,0 +1,30 @@
<?xml version="1.0"?>
<psalm
errorLevel="1"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
findUnusedCode="false"
>
<projectFiles>
<directory name="lib/Doctrine/Deprecations" />
<directory name="tests/Doctrine/Deprecations" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<plugins>
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
</plugins>
<issueHandlers>
<DeprecatedMethod>
<errorLevel type="suppress">
<!-- Remove when dropping support for PHPUnit 9.6 -->
<referencedMethod name="PHPUnit\Framework\TestCase::expectDeprecation"/>
<referencedMethod name="PHPUnit\Framework\TestCase::expectDeprecationMessage"/>
</errorLevel>
</DeprecatedMethod>
</issueHandlers>
</psalm>

View File

@@ -1008,7 +1008,7 @@ array_pair:
| expr { $$ = Expr\ArrayItem[$1, null, false]; }
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| ampersand variable { $$ = Expr\ArrayItem[$2, null, true]; }
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; }
| T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); }
;
encaps_list:

View File

@@ -221,7 +221,10 @@ non_empty_class_const_list:
;
class_const:
identifier_maybe_reserved '=' expr { $$ = Node\Const_[$1, $3]; }
T_STRING '=' expr
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
| semi_reserved '=' expr
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
;
inner_statement_list_ex:
@@ -722,6 +725,9 @@ class_statement:
| optional_attributes method_modifiers T_CONST class_const_list semi
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
$this->checkClassConst($$, #2); }
| optional_attributes method_modifiers T_CONST type_expr class_const_list semi
{ $$ = new Stmt\ClassConst($5, $2, attributes(), $1, $4);
$this->checkClassConst($$, #2); }
| optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')'
optional_return_type method_body
{ $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]];
@@ -943,8 +949,8 @@ expr:
;
anonymous_class:
optional_attributes T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
optional_attributes class_entry_type ctor_arguments extends_from implements_list '{' class_statement_list '}'
{ $$ = array(Stmt\Class_[null, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
$this->checkClass($$[0], -1); }
;
@@ -1040,6 +1046,8 @@ constant:
class_constant:
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved
{ $$ = Expr\ClassConstFetch[$1, $3]; }
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}'
{ $$ = Expr\ClassConstFetch[$1, $4]; }
/* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be
an unfinished static property fetch or unfinished scoped call. */
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error
@@ -1194,7 +1202,7 @@ array_pair:
| expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; }
| expr T_DOUBLE_ARROW ampersand variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; }
| T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; }
| T_ELLIPSIS expr { $$ = new Expr\ArrayItem($2, null, false, attributes(), true); }
| /* empty */ { $$ = null; }
;

View File

@@ -19,6 +19,8 @@ class ClassConst implements PhpParser\Builder
/** @var Node\AttributeGroup[] */
protected $attributeGroups = [];
/** @var Identifier|Node\Name|Node\ComplexType */
protected $type;
/**
* Creates a class constant builder
@@ -116,6 +118,19 @@ class ClassConst implements PhpParser\Builder
return $this;
}
/**
* Sets the constant type.
*
* @param string|Node\Name|Identifier|Node\ComplexType $type
*
* @return $this
*/
public function setType($type) {
$this->type = BuilderHelpers::normalizeType($type);
return $this;
}
/**
* Returns the built class node.
*
@@ -126,7 +141,8 @@ class ClassConst implements PhpParser\Builder
$this->constants,
$this->flags,
$this->attributes,
$this->attributeGroups
$this->attributeGroups,
$this->type
);
}
}

View File

@@ -349,15 +349,15 @@ class BuilderFactory
/**
* Creates a class constant fetch node.
*
* @param string|Name|Expr $class Class name
* @param string|Identifier $name Constant name
* @param string|Name|Expr $class Class name
* @param string|Identifier|Expr $name Constant name
*
* @return Expr\ClassConstFetch
*/
public function classConstFetch($class, $name): Expr\ClassConstFetch {
return new Expr\ClassConstFetch(
BuilderHelpers::normalizeNameOrExpr($class),
BuilderHelpers::normalizeIdentifier($name)
BuilderHelpers::normalizeIdentifierOrExpr($name)
);
}

View File

@@ -19,6 +19,8 @@ class PrintableNewAnonClassNode extends Expr
{
/** @var Node\AttributeGroup[] PHP attribute groups */
public $attrGroups;
/** @var int Modifiers */
public $flags;
/** @var Node\Arg[] Arguments */
public $args;
/** @var null|Node\Name Name of extended class */
@@ -29,11 +31,12 @@ class PrintableNewAnonClassNode extends Expr
public $stmts;
public function __construct(
array $attrGroups, array $args, Node\Name $extends = null, array $implements,
array $attrGroups, int $flags, array $args, Node\Name $extends = null, array $implements,
array $stmts, array $attributes
) {
parent::__construct($attributes);
$this->attrGroups = $attrGroups;
$this->flags = $flags;
$this->args = $args;
$this->extends = $extends;
$this->implements = $implements;
@@ -46,7 +49,7 @@ class PrintableNewAnonClassNode extends Expr
// We don't assert that $class->name is null here, to allow consumers to assign unique names
// to anonymous classes for their own purposes. We simplify ignore the name here.
return new self(
$class->attrGroups, $newNode->args, $class->extends, $class->implements,
$class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements,
$class->stmts, $newNode->getAttributes()
);
}
@@ -56,6 +59,6 @@ class PrintableNewAnonClassNode extends Expr
}
public function getSubNodeNames() : array {
return ['attrGroups', 'args', 'extends', 'implements', 'stmts'];
return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts'];
}
}

View File

@@ -10,15 +10,15 @@ class ClassConstFetch extends Expr
{
/** @var Name|Expr Class name */
public $class;
/** @var Identifier|Error Constant name */
/** @var Identifier|Expr|Error Constant name */
public $name;
/**
* Constructs a class const fetch node.
*
* @param Name|Expr $class Class name
* @param string|Identifier|Error $name Constant name
* @param array $attributes Additional attributes
* @param Name|Expr $class Class name
* @param string|Identifier|Expr|Error $name Constant name
* @param array $attributes Additional attributes
*/
public function __construct($class, $name, array $attributes = []) {
$this->attributes = $attributes;
@@ -29,7 +29,7 @@ class ClassConstFetch extends Expr
public function getSubNodeNames() : array {
return ['class', 'name'];
}
public function getType() : string {
return 'Expr_ClassConstFetch';
}

View File

@@ -6,7 +6,10 @@ use PhpParser\NodeAbstract;
class Name extends NodeAbstract
{
/** @var string[] Parts of the name */
/**
* @var string[] Parts of the name
* @deprecated Use getParts() instead
*/
public $parts;
private static $specialClassNames = [
@@ -30,6 +33,15 @@ class Name extends NodeAbstract
return ['parts'];
}
/**
* Get parts of name (split by the namespace separator).
*
* @return string[] Parts of name
*/
public function getParts(): array {
return $this->parts;
}
/**
* Gets the first part of the name, i.e. everything before the first namespace separator.
*

View File

@@ -10,31 +10,36 @@ class ClassConst extends Node\Stmt
public $flags;
/** @var Node\Const_[] Constant declarations */
public $consts;
/** @var Node\AttributeGroup[] */
/** @var Node\AttributeGroup[] PHP attribute groups */
public $attrGroups;
/** @var Node\Identifier|Node\Name|Node\ComplexType|null Type declaration */
public $type;
/**
* Constructs a class const list node.
*
* @param Node\Const_[] $consts Constant declarations
* @param int $flags Modifiers
* @param array $attributes Additional attributes
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
* @param Node\Const_[] $consts Constant declarations
* @param int $flags Modifiers
* @param array $attributes Additional attributes
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
* @param null|string|Node\Identifier|Node\Name|Node\ComplexType $type Type declaration
*/
public function __construct(
array $consts,
int $flags = 0,
array $attributes = [],
array $attrGroups = []
array $attrGroups = [],
$type = null
) {
$this->attributes = $attributes;
$this->flags = $flags;
$this->consts = $consts;
$this->attrGroups = $attrGroups;
$this->type = \is_string($type) ? new Node\Identifier($type) : $type;
}
public function getSubNodeNames() : array {
return ['attrGroups', 'flags', 'consts'];
return ['attrGroups', 'flags', 'type', 'consts'];
}
/**

View File

@@ -2627,7 +2627,7 @@ class Php5 extends \PhpParser\ParserAbstract
$this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, true, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes);
},
552 => function ($stackPos) {
$this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, false, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes, true, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes);
$this->semValue = new Expr\ArrayItem($this->semStack[$stackPos-(2-2)], null, false, $this->startAttributeStack[$stackPos-(2-1)] + $this->endAttributes, true);
},
553 => function ($stackPos) {
$this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)];

File diff suppressed because it is too large Load Diff

View File

@@ -529,7 +529,7 @@ class Standard extends PrettyPrinterAbstract
}
protected function pExpr_StaticCall(Expr\StaticCall $node) {
return $this->pDereferenceLhs($node->class) . '::'
return $this->pStaticDereferenceLhs($node->class) . '::'
. ($node->name instanceof Expr
? ($node->name instanceof Expr\Variable
? $this->p($node->name)
@@ -606,7 +606,7 @@ class Standard extends PrettyPrinterAbstract
}
protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) {
return $this->pDereferenceLhs($node->class) . '::' . $this->p($node->name);
return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name);
}
protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
@@ -618,7 +618,7 @@ class Standard extends PrettyPrinterAbstract
}
protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
}
protected function pExpr_ShellExec(Expr\ShellExec $node) {
@@ -814,7 +814,9 @@ class Standard extends PrettyPrinterAbstract
protected function pStmt_ClassConst(Stmt\ClassConst $node) {
return $this->pAttrGroups($node->attrGroups)
. $this->pModifiers($node->flags)
. 'const ' . $this->pCommaSeparated($node->consts) . ';';
. 'const '
. (null !== $node->type ? $this->p($node->type) . ' ' : '')
. $this->pCommaSeparated($node->consts) . ';';
}
protected function pStmt_Function(Stmt\Function_ $node) {
@@ -1067,6 +1069,14 @@ class Standard extends PrettyPrinterAbstract
}
}
protected function pStaticDereferenceLhs(Node $node) {
if (!$this->staticDereferenceLhsRequiresParens($node)) {
return $this->p($node);
} else {
return '(' . $this->p($node) . ')';
}
}
protected function pCallLhs(Node $node) {
if (!$this->callLhsRequiresParens($node)) {
return $this->p($node);
@@ -1075,9 +1085,12 @@ class Standard extends PrettyPrinterAbstract
}
}
protected function pNewVariable(Node $node) {
// TODO: This is not fully accurate.
return $this->pDereferenceLhs($node);
protected function pNewVariable(Node $node): string {
if (!$this->newOperandRequiresParens($node)) {
return $this->p($node);
} else {
return '(' . $this->p($node) . ')';
}
}
/**

View File

@@ -21,6 +21,8 @@ abstract class PrettyPrinterAbstract
const FIXUP_BRACED_NAME = 4; // Name operand that may require bracing
const FIXUP_VAR_BRACED_NAME = 5; // Name operand that may require ${} bracing
const FIXUP_ENCAPSED = 6; // Encapsed string part
const FIXUP_NEW = 7; // New/instanceof operand
const FIXUP_STATIC_DEREF_LHS = 8; // LHS of static dereferencing operation
protected $precedenceMap = [
// [precedence, associativity]
@@ -977,6 +979,19 @@ abstract class PrettyPrinterAbstract
return '(' . $this->p($subNode) . ')';
}
break;
case self::FIXUP_STATIC_DEREF_LHS:
if ($this->staticDereferenceLhsRequiresParens($subNode)
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)
) {
return '(' . $this->p($subNode) . ')';
}
break;
case self::FIXUP_NEW:
if ($this->newOperandRequiresParens($subNode)
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)) {
return '(' . $this->p($subNode) . ')';
}
break;
case self::FIXUP_BRACED_NAME:
case self::FIXUP_VAR_BRACED_NAME:
if ($subNode instanceof Expr
@@ -1047,13 +1062,26 @@ abstract class PrettyPrinterAbstract
}
/**
* Determines whether the LHS of a dereferencing operation must be wrapped in parenthesis.
* Determines whether the LHS of an array/object operation must be wrapped in parentheses.
*
* @param Node $node LHS of dereferencing operation
*
* @return bool Whether parentheses are required
*/
protected function dereferenceLhsRequiresParens(Node $node) : bool {
// A constant can occur on the LHS of an array/object deref, but not a static deref.
return $this->staticDereferenceLhsRequiresParens($node)
&& !$node instanceof Expr\ConstFetch;
}
/**
* Determines whether the LHS of a static operation must be wrapped in parentheses.
*
* @param Node $node LHS of dereferencing operation
*
* @return bool Whether parentheses are required
*/
protected function staticDereferenceLhsRequiresParens(Node $node): bool {
return !($node instanceof Expr\Variable
|| $node instanceof Node\Name
|| $node instanceof Expr\ArrayDimFetch
@@ -1066,10 +1094,31 @@ abstract class PrettyPrinterAbstract
|| $node instanceof Expr\StaticCall
|| $node instanceof Expr\Array_
|| $node instanceof Scalar\String_
|| $node instanceof Expr\ConstFetch
|| $node instanceof Expr\ClassConstFetch);
}
/**
* Determines whether an expression used in "new" or "instanceof" requires parentheses.
*
* @param Node $node New or instanceof operand
*
* @return bool Whether parentheses are required
*/
protected function newOperandRequiresParens(Node $node): bool {
if ($node instanceof Node\Name || $node instanceof Expr\Variable) {
return false;
}
if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch ||
$node instanceof Expr\NullsafePropertyFetch
) {
return $this->newOperandRequiresParens($node->var);
}
if ($node instanceof Expr\StaticPropertyFetch) {
return $this->newOperandRequiresParens($node->class);
}
return true;
}
/**
* Print modifiers, including trailing whitespace.
*
@@ -1171,7 +1220,7 @@ abstract class PrettyPrinterAbstract
Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT],
Expr\Instanceof_::class => [
'expr' => self::FIXUP_PREC_LEFT,
'class' => self::FIXUP_PREC_RIGHT, // TODO: FIXUP_NEW_VARIABLE
'class' => self::FIXUP_NEW,
],
Expr\Ternary::class => [
'cond' => self::FIXUP_PREC_LEFT,
@@ -1179,10 +1228,13 @@ abstract class PrettyPrinterAbstract
],
Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],
Expr\StaticCall::class => ['class' => self::FIXUP_DEREF_LHS],
Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS],
Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],
Expr\ClassConstFetch::class => ['var' => self::FIXUP_DEREF_LHS],
Expr\New_::class => ['class' => self::FIXUP_DEREF_LHS], // TODO: FIXUP_NEW_VARIABLE
Expr\ClassConstFetch::class => [
'class' => self::FIXUP_STATIC_DEREF_LHS,
'name' => self::FIXUP_BRACED_NAME,
],
Expr\New_::class => ['class' => self::FIXUP_NEW],
Expr\MethodCall::class => [
'var' => self::FIXUP_DEREF_LHS,
'name' => self::FIXUP_BRACED_NAME,
@@ -1192,7 +1244,7 @@ abstract class PrettyPrinterAbstract
'name' => self::FIXUP_BRACED_NAME,
],
Expr\StaticPropertyFetch::class => [
'class' => self::FIXUP_DEREF_LHS,
'class' => self::FIXUP_STATIC_DEREF_LHS,
'name' => self::FIXUP_VAR_BRACED_NAME,
],
Expr\PropertyFetch::class => [
@@ -1278,6 +1330,7 @@ abstract class PrettyPrinterAbstract
'Param->default' => $stripEquals,
'Stmt_Break->num' => $stripBoth,
'Stmt_Catch->var' => $stripLeft,
'Stmt_ClassConst->type' => $stripRight,
'Stmt_ClassMethod->returnType' => $stripColon,
'Stmt_Class->extends' => ['left' => \T_EXTENDS],
'Stmt_Enum->scalarType' => $stripColon,
@@ -1319,6 +1372,7 @@ abstract class PrettyPrinterAbstract
'Stmt_Break->num' => [\T_BREAK, false, ' ', null],
'Stmt_Catch->var' => [null, false, ' ', null],
'Stmt_ClassMethod->returnType' => [')', false, ' : ', null],
'Stmt_ClassConst->type' => [\T_CONST, false, ' ', null],
'Stmt_Class->extends' => [null, false, ' extends ', null],
'Stmt_Enum->scalarType' => [null, false, ' : ', null],
'Stmt_EnumCase->expr' => [null, false, ' = ', null],
@@ -1508,6 +1562,7 @@ abstract class PrettyPrinterAbstract
'Stmt_ClassMethod->flags' => \T_FUNCTION,
'Stmt_Class->flags' => \T_CLASS,
'Stmt_Property->flags' => \T_VARIABLE,
'Expr_PrintableNewAnonClass->flags' => \T_CLASS,
'Param->flags' => \T_VARIABLE,
//'Stmt_TraitUseAdaptation_Alias->newModifier' => 0, // TODO
];

View File

@@ -181,6 +181,7 @@ final class ContextFactory
$currentNamespace = $this->parseNamespace($tokens);
break;
case T_CLASS:
case T_TRAIT:
// Fast-forward the iterator through the class so that any
// T_USE tokens found within are skipped - these are not
// valid namespace use statements so should be ignored.

View File

@@ -15,6 +15,8 @@ For the complete list of supported PHPDoc features check out PHPStan documentati
* [PHPDoc Types](https://phpstan.org/writing-php-code/phpdoc-types) (list of PHPDoc types)
* [phpdoc-parser API Reference](https://phpstan.github.io/phpdoc-parser/namespace-PHPStan.PhpDocParser.html) with all the AST node types etc.
This parser also supports parsing [Doctrine Annotations](https://github.com/doctrine/annotations). The AST nodes live in the [PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine namespace](https://phpstan.github.io/phpdoc-parser/namespace-PHPStan.PhpDocParser.Ast.PhpDoc.Doctrine.html). The support needs to be turned on by setting `bool $parseDoctrineAnnotations` to `true` in `Lexer` and `PhpDocParser` class constructors.
## Installation
```

View File

@@ -6,6 +6,7 @@
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/annotations": "^2.0",
"nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",

View File

@@ -0,0 +1,42 @@
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Ast\ConstExpr;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function sprintf;
use function str_replace;
use function strlen;
use function substr;
class DoctrineConstExprStringNode extends ConstExprStringNode
{
use NodeAttributes;
/** @var string */
public $value;
public function __construct(string $value)
{
parent::__construct($value);
$this->value = $value;
}
public function __toString(): string
{
return self::escape($this->value);
}
public static function unescape(string $value): string
{
// from https://github.com/doctrine/annotations/blob/a9ec7af212302a75d1f92fa65d3abfbd16245a2a/lib/Doctrine/Common/Annotations/DocLexer.php#L103-L107
return str_replace('""', '"', substr($value, 1, strlen($value) - 2));
}
private static function escape(string $value): string
{
// from https://github.com/phpstan/phpdoc-parser/issues/205#issuecomment-1662323656
return sprintf('"%s"', str_replace('"', '""', $value));
}
}

View File

@@ -0,0 +1,35 @@
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;
class DoctrineAnnotation implements Node
{
use NodeAttributes;
/** @var string */
public $name;
/** @var list<DoctrineArgument> */
public $arguments;
/**
* @param list<DoctrineArgument> $arguments
*/
public function __construct(string $name, array $arguments)
{
$this->name = $name;
$this->arguments = $arguments;
}
public function __toString(): string
{
$arguments = implode(', ', $this->arguments);
return $this->name . '(' . $arguments . ')';
}
}

View File

@@ -0,0 +1,43 @@
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
/**
* @phpstan-type ValueType = DoctrineAnnotation|IdentifierTypeNode|DoctrineArray|ConstExprNode
*/
class DoctrineArgument implements Node
{
use NodeAttributes;
/** @var IdentifierTypeNode|null */
public $key;
/** @var ValueType */
public $value;
/**
* @param ValueType $value
*/
public function __construct(?IdentifierTypeNode $key, $value)
{
$this->key = $key;
$this->value = $value;
}
public function __toString(): string
{
if ($this->key === null) {
return (string) $this->value;
}
return $this->key . '=' . $this->value;
}
}

View File

@@ -0,0 +1,32 @@
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use function implode;
class DoctrineArray implements Node
{
use NodeAttributes;
/** @var list<DoctrineArrayItem> */
public $items;
/**
* @param list<DoctrineArrayItem> $items
*/
public function __construct(array $items)
{
$this->items = $items;
}
public function __toString(): string
{
$items = implode(', ', $this->items);
return '{' . $items . '}';
}
}

View File

@@ -0,0 +1,47 @@
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
/**
* @phpstan-import-type ValueType from DoctrineArgument
* @phpstan-type KeyType = ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode|null
*/
class DoctrineArrayItem implements Node
{
use NodeAttributes;
/** @var KeyType */
public $key;
/** @var ValueType */
public $value;
/**
* @param KeyType $key
* @param ValueType $value
*/
public function __construct($key, $value)
{
$this->key = $key;
$this->value = $value;
}
public function __toString(): string
{
if ($this->key === null) {
return (string) $this->value;
}
return $this->key . '=' . $this->value;
}
}

View File

@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use function trim;
class DoctrineTagValueNode implements PhpDocTagValueNode
{
use NodeAttributes;
/** @var DoctrineAnnotation */
public $annotation;
/** @var string (may be empty) */
public $description;
public function __construct(
DoctrineAnnotation $annotation,
string $description
)
{
$this->annotation = $annotation;
$this->description = $description;
}
public function __toString(): string
{
return trim("{$this->annotation} {$this->description}");
}
}

View File

@@ -3,6 +3,7 @@
namespace PHPStan\PhpDocParser\Ast\PhpDoc;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
use function trim;
class PhpDocTagNode implements PhpDocChildNode
@@ -25,6 +26,10 @@ class PhpDocTagNode implements PhpDocChildNode
public function __toString(): string
{
if ($this->value instanceof DoctrineTagValueNode) {
return (string) $this->value;
}
return trim("{$this->name} {$this->value}");
}

View File

@@ -30,23 +30,25 @@ class Lexer
public const TOKEN_OPEN_PHPDOC = 15;
public const TOKEN_CLOSE_PHPDOC = 16;
public const TOKEN_PHPDOC_TAG = 17;
public const TOKEN_FLOAT = 18;
public const TOKEN_INTEGER = 19;
public const TOKEN_SINGLE_QUOTED_STRING = 20;
public const TOKEN_DOUBLE_QUOTED_STRING = 21;
public const TOKEN_IDENTIFIER = 22;
public const TOKEN_THIS_VARIABLE = 23;
public const TOKEN_VARIABLE = 24;
public const TOKEN_HORIZONTAL_WS = 25;
public const TOKEN_PHPDOC_EOL = 26;
public const TOKEN_OTHER = 27;
public const TOKEN_END = 28;
public const TOKEN_COLON = 29;
public const TOKEN_WILDCARD = 30;
public const TOKEN_OPEN_CURLY_BRACKET = 31;
public const TOKEN_CLOSE_CURLY_BRACKET = 32;
public const TOKEN_NEGATED = 33;
public const TOKEN_ARROW = 34;
public const TOKEN_DOCTRINE_TAG = 18;
public const TOKEN_FLOAT = 19;
public const TOKEN_INTEGER = 20;
public const TOKEN_SINGLE_QUOTED_STRING = 21;
public const TOKEN_DOUBLE_QUOTED_STRING = 22;
public const TOKEN_DOCTRINE_ANNOTATION_STRING = 23;
public const TOKEN_IDENTIFIER = 24;
public const TOKEN_THIS_VARIABLE = 25;
public const TOKEN_VARIABLE = 26;
public const TOKEN_HORIZONTAL_WS = 27;
public const TOKEN_PHPDOC_EOL = 28;
public const TOKEN_OTHER = 29;
public const TOKEN_END = 30;
public const TOKEN_COLON = 31;
public const TOKEN_WILDCARD = 32;
public const TOKEN_OPEN_CURLY_BRACKET = 33;
public const TOKEN_CLOSE_CURLY_BRACKET = 34;
public const TOKEN_NEGATED = 35;
public const TOKEN_ARROW = 36;
public const TOKEN_LABELS = [
self::TOKEN_REFERENCE => '\'&\'',
@@ -72,11 +74,13 @@ class Lexer
self::TOKEN_OPEN_PHPDOC => '\'/**\'',
self::TOKEN_CLOSE_PHPDOC => '\'*/\'',
self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG',
self::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG',
self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL',
self::TOKEN_FLOAT => 'TOKEN_FLOAT',
self::TOKEN_INTEGER => 'TOKEN_INTEGER',
self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING',
self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING',
self::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING',
self::TOKEN_IDENTIFIER => 'type',
self::TOKEN_THIS_VARIABLE => '\'$this\'',
self::TOKEN_VARIABLE => 'variable',
@@ -90,9 +94,17 @@ class Lexer
public const TYPE_OFFSET = 1;
public const LINE_OFFSET = 2;
/** @var bool */
private $parseDoctrineAnnotations;
/** @var string|null */
private $regexp;
public function __construct(bool $parseDoctrineAnnotations = false)
{
$this->parseDoctrineAnnotations = $parseDoctrineAnnotations;
}
/**
* @return list<array{string, int, int}>
*/
@@ -160,17 +172,22 @@ class Lexer
self::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+',
self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?',
self::TOKEN_FLOAT => '(?:-?[0-9]++(_[0-9]++)*\\.[0-9]*(_[0-9]++)*+(?:e-?[0-9]++(_[0-9]++)*)?)|(?:-?[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e-?[0-9]++(_[0-9]++)*)?)|(?:-?[0-9]++(_[0-9]++)*e-?[0-9]++(_[0-9]++)*)',
self::TOKEN_INTEGER => '-?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))',
self::TOKEN_FLOAT => '[+\-]?(?:(?:[0-9]++(_[0-9]++)*\\.[0-9]*+(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]++(_[0-9]++)*e[+\-]?[0-9]++(_[0-9]++)*))',
self::TOKEN_INTEGER => '[+\-]?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))',
self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'',
self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"',
self::TOKEN_WILDCARD => '\\*',
// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL
self::TOKEN_OTHER => '(?:(?!\\*/)[^\\s])++',
];
if ($this->parseDoctrineAnnotations) {
$patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*';
$patterns[self::TOKEN_DOCTRINE_ANNOTATION_STRING] = '"(?:""|[^"])*+"';
}
// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL
$patterns[self::TOKEN_OTHER] = '(?:(?!\\*/)[^\\s])++';
foreach ($patterns as $type => &$pattern) {
$pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')';
}

View File

@@ -23,6 +23,9 @@ class ConstExprParser
/** @var bool */
private $useIndexAttributes;
/** @var bool */
private $parseDoctrineStrings;
/**
* @param array{lines?: bool, indexes?: bool} $usedAttributes
*/
@@ -36,6 +39,24 @@ class ConstExprParser
$this->quoteAwareConstExprString = $quoteAwareConstExprString;
$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
$this->parseDoctrineStrings = false;
}
/**
* @internal
*/
public function toDoctrine(): self
{
$self = new self(
$this->unescapeStrings,
$this->quoteAwareConstExprString,
[
'lines' => $this->useLinesAttributes,
'indexes' => $this->useIndexAttributes,
]
);
$self->parseDoctrineStrings = true;
return $self;
}
public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\ConstExpr\ConstExprNode
@@ -66,7 +87,41 @@ class ConstExprParser
);
}
if ($this->parseDoctrineStrings && $tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
$value = $tokens->currentTokenValue();
$tokens->next();
return $this->enrichWithAttributes(
$tokens,
new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($value)),
$startLine,
$startIndex
);
}
if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
if ($this->parseDoctrineStrings) {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
throw new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_DOUBLE_QUOTED_STRING,
null,
$tokens->currentTokenLine()
);
}
$value = $tokens->currentTokenValue();
$tokens->next();
return $this->enrichWithAttributes(
$tokens,
$this->parseDoctrineString($value, $tokens),
$startLine,
$startIndex
);
}
$value = $tokens->currentTokenValue();
$type = $tokens->currentTokenType();
if ($trimStrings) {
@@ -214,6 +269,23 @@ class ConstExprParser
}
/**
* This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting
* to the next token.
*/
public function parseDoctrineString(string $text, TokenIterator $tokens): Ast\ConstExpr\DoctrineConstExprStringNode
{
// Because of how Lexer works, a valid Doctrine string
// can consist of a sequence of TOKEN_DOUBLE_QUOTED_STRING and TOKEN_DOCTRINE_ANNOTATION_STRING
while ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING, Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
$text .= $tokens->currentTokenValue();
$tokens->next();
}
return new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($text));
}
private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprArrayItemNode
{
$startLine = $tokens->currentTokenLine();
@@ -245,22 +317,14 @@ class ConstExprParser
*/
private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex): Ast\ConstExpr\ConstExprNode
{
$endLine = $tokens->currentTokenLine();
$endIndex = $tokens->currentTokenIndex();
if ($this->useLinesAttributes) {
$node->setAttribute(Ast\Attribute::START_LINE, $startLine);
$node->setAttribute(Ast\Attribute::END_LINE, $endLine);
$node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
}
if ($this->useIndexAttributes) {
$tokensArray = $tokens->getTokens();
$endIndex--;
if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
$endIndex--;
}
$node->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
$node->setAttribute(Ast\Attribute::END_INDEX, $endIndex);
$node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
}
return $node;

View File

@@ -2,15 +2,25 @@
namespace PHPStan\PhpDocParser\Parser;
use LogicException;
use PHPStan\PhpDocParser\Ast;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\ShouldNotHappenException;
use function array_key_exists;
use function array_values;
use function count;
use function rtrim;
use function str_replace;
use function trim;
/**
* @phpstan-import-type ValueType from Doctrine\DoctrineArgument as DoctrineValueType
*/
class PhpDocParser
{
@@ -25,18 +35,27 @@ class PhpDocParser
/** @var ConstExprParser */
private $constantExprParser;
/** @var ConstExprParser */
private $doctrineConstantExprParser;
/** @var bool */
private $requireWhitespaceBeforeDescription;
/** @var bool */
private $preserveTypeAliasesWithInvalidTypes;
/** @var bool */
private $parseDoctrineAnnotations;
/** @var bool */
private $useLinesAttributes;
/** @var bool */
private $useIndexAttributes;
/** @var bool */
private $textBetweenTagsBelongsToDescription;
/**
* @param array{lines?: bool, indexes?: bool} $usedAttributes
*/
@@ -45,15 +64,20 @@ class PhpDocParser
ConstExprParser $constantExprParser,
bool $requireWhitespaceBeforeDescription = false,
bool $preserveTypeAliasesWithInvalidTypes = false,
array $usedAttributes = []
array $usedAttributes = [],
bool $parseDoctrineAnnotations = false,
bool $textBetweenTagsBelongsToDescription = false
)
{
$this->typeParser = $typeParser;
$this->constantExprParser = $constantExprParser;
$this->doctrineConstantExprParser = $constantExprParser->toDoctrine();
$this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription;
$this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes;
$this->parseDoctrineAnnotations = $parseDoctrineAnnotations;
$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
$this->textBetweenTagsBelongsToDescription = $textBetweenTagsBelongsToDescription;
}
@@ -64,10 +88,44 @@ class PhpDocParser
$children = [];
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
$children[] = $this->parseChild($tokens);
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
if ($this->parseDoctrineAnnotations) {
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
$lastChild = $this->parseChild($tokens);
$children[] = $lastChild;
while (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
if (
$lastChild instanceof Ast\PhpDoc\PhpDocTagNode
&& (
$lastChild->value instanceof Doctrine\DoctrineTagValueNode
|| $lastChild->value instanceof Ast\PhpDoc\GenericTagValueNode
)
) {
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
break;
}
$lastChild = $this->parseChild($tokens);
$children[] = $lastChild;
continue;
}
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
break;
}
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
break;
}
$lastChild = $this->parseChild($tokens);
$children[] = $lastChild;
}
}
} else {
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
$children[] = $this->parseChild($tokens);
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
$children[] = $this->parseChild($tokens);
}
}
}
@@ -105,6 +163,7 @@ class PhpDocParser
}
/** @phpstan-impure */
private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode
{
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {
@@ -113,6 +172,26 @@ class PhpDocParser
return $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex);
}
if ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_TAG)) {
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
$tag = $tokens->currentTokenValue();
$tokens->next();
$tagStartLine = $tokens->currentTokenLine();
$tagStartIndex = $tokens->currentTokenIndex();
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocTagNode(
$tag,
$this->enrichWithAttributes(
$tokens,
$this->parseDoctrineTagValue($tokens, $tag),
$tagStartLine,
$tagStartIndex
)
), $startLine, $startIndex);
}
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
$text = $this->parseText($tokens);
@@ -127,23 +206,14 @@ class PhpDocParser
*/
private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex): Ast\Node
{
$endLine = $tokens->currentTokenLine();
$endIndex = $tokens->currentTokenIndex();
if ($this->useLinesAttributes) {
$tag->setAttribute(Ast\Attribute::START_LINE, $startLine);
$tag->setAttribute(Ast\Attribute::END_LINE, $endLine);
$tag->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
}
if ($this->useIndexAttributes) {
$tokensArray = $tokens->getTokens();
$endIndex--;
if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
$endIndex--;
}
$tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
$tag->setAttribute(Ast\Attribute::END_INDEX, $endIndex);
$tag->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
}
return $tag;
@@ -154,29 +224,144 @@ class PhpDocParser
{
$text = '';
while (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
$text .= $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END);
$endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
if ($this->textBetweenTagsBelongsToDescription) {
$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
}
$savepoint = false;
// if the next token is EOL, everything below is skipped and empty string is returned
while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
$text .= $tmpText;
// stop if we're not at EOL - meaning it's the end of PHPDoc
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
break;
}
if ($this->textBetweenTagsBelongsToDescription) {
if (!$savepoint) {
$tokens->pushSavePoint();
$savepoint = true;
} elseif ($tmpText !== '') {
$tokens->dropSavePoint();
$tokens->pushSavePoint();
}
}
$tokens->pushSavePoint();
$tokens->next();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)) {
// if we're at EOL, check what's next
// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {
$tokens->rollback();
break;
}
// otherwise if the next is text, continue building the description string
$tokens->dropSavePoint();
$text .= "\n";
$text .= $tokens->getDetectedNewline() ?? "\n";
}
if ($savepoint) {
$tokens->rollback();
$text = rtrim($text, $tokens->getDetectedNewline() ?? "\n");
}
return new Ast\PhpDoc\PhpDocTextNode(trim($text, " \t"));
}
private function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens): string
{
$text = '';
$endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
if ($this->textBetweenTagsBelongsToDescription) {
$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
}
$savepoint = false;
// if the next token is EOL, everything below is skipped and empty string is returned
while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
$text .= $tmpText;
// stop if we're not at EOL - meaning it's the end of PHPDoc
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
if (!$tokens->isPrecededByHorizontalWhitespace()) {
return trim($text . $this->parseText($tokens)->text, " \t");
}
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {
$tokens->pushSavePoint();
$child = $this->parseChild($tokens);
if ($child instanceof Ast\PhpDoc\PhpDocTagNode) {
if (
$child->value instanceof Ast\PhpDoc\GenericTagValueNode
|| $child->value instanceof Doctrine\DoctrineTagValueNode
) {
$tokens->rollback();
break;
}
if ($child->value instanceof Ast\PhpDoc\InvalidTagValueNode) {
$tokens->rollback();
$tokens->pushSavePoint();
$tokens->next();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
$tokens->rollback();
break;
}
$tokens->rollback();
return trim($text . $this->parseText($tokens)->text, " \t");
}
}
$tokens->rollback();
return trim($text . $this->parseText($tokens)->text, " \t");
}
break;
}
if ($this->textBetweenTagsBelongsToDescription) {
if (!$savepoint) {
$tokens->pushSavePoint();
$savepoint = true;
} elseif ($tmpText !== '') {
$tokens->dropSavePoint();
$tokens->pushSavePoint();
}
}
$tokens->pushSavePoint();
$tokens->next();
// if we're at EOL, check what's next
// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {
$tokens->rollback();
break;
}
// otherwise if the next is text, continue building the description string
$tokens->dropSavePoint();
$text .= $tokens->getDetectedNewline() ?? "\n";
}
if ($savepoint) {
$tokens->rollback();
$text = rtrim($text, $tokens->getDetectedNewline() ?? "\n");
}
return trim($text, " \t");
}
public function parseTag(TokenIterator $tokens): Ast\PhpDoc\PhpDocTagNode
{
$tag = $tokens->currentTokenValue();
@@ -308,7 +493,17 @@ class PhpDocParser
break;
default:
if ($this->parseDoctrineAnnotations) {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
$tagValue = $this->parseDoctrineTagValue($tokens, $tag);
} else {
$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens));
}
break;
}
$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens));
break;
}
@@ -323,6 +518,308 @@ class PhpDocParser
}
private function parseDoctrineTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\PhpDocTagValueNode
{
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
return new Doctrine\DoctrineTagValueNode(
$this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineAnnotation($tag, $this->parseDoctrineArguments($tokens, false)),
$startLine,
$startIndex
),
$this->parseOptionalDescriptionAfterDoctrineTag($tokens)
);
}
/**
* @return list<Doctrine\DoctrineArgument>
*/
private function parseDoctrineArguments(TokenIterator $tokens, bool $deep): array
{
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
return [];
}
if (!$deep) {
$tokens->addEndOfLineToSkippedTokens();
}
$arguments = [];
try {
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
do {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
break;
}
$arguments[] = $this->parseDoctrineArgument($tokens);
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
} finally {
if (!$deep) {
$tokens->removeEndOfLineFromSkippedTokens();
}
}
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
return $arguments;
}
private function parseDoctrineArgument(TokenIterator $tokens): Doctrine\DoctrineArgument
{
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
return $this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),
$startLine,
$startIndex
);
}
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
try {
$tokens->pushSavePoint();
$currentValue = $tokens->currentTokenValue();
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
$key = $this->enrichWithAttributes(
$tokens,
new IdentifierTypeNode($currentValue),
$startLine,
$startIndex
);
$tokens->consumeTokenType(Lexer::TOKEN_EQUAL);
$value = $this->parseDoctrineArgumentValue($tokens);
$tokens->dropSavePoint();
return $this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineArgument($key, $value),
$startLine,
$startIndex
);
} catch (ParserException $e) {
$tokens->rollback();
return $this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),
$startLine,
$startIndex
);
}
}
/**
* @return DoctrineValueType
*/
private function parseDoctrineArgumentValue(TokenIterator $tokens)
{
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG)) {
$name = $tokens->currentTokenValue();
$tokens->next();
return $this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineAnnotation($name, $this->parseDoctrineArguments($tokens, true)),
$startLine,
$startIndex
);
}
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) {
$items = [];
do {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
break;
}
$items[] = $this->parseDoctrineArrayItem($tokens);
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
return $this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineArray($items),
$startLine,
$startIndex
);
}
$currentTokenValue = $tokens->currentTokenValue();
$tokens->pushSavePoint(); // because of ConstFetchNode
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
$identifier = $this->enrichWithAttributes(
$tokens,
new Ast\Type\IdentifierTypeNode($currentTokenValue),
$startLine,
$startIndex
);
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
$tokens->dropSavePoint();
return $identifier;
}
$tokens->rollback(); // because of ConstFetchNode
} else {
$tokens->dropSavePoint(); // because of ConstFetchNode
}
$currentTokenValue = $tokens->currentTokenValue();
$currentTokenType = $tokens->currentTokenType();
$currentTokenOffset = $tokens->currentTokenOffset();
$currentTokenLine = $tokens->currentTokenLine();
try {
$constExpr = $this->doctrineConstantExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
return $constExpr;
} catch (LogicException $e) {
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
}
private function parseDoctrineArrayItem(TokenIterator $tokens): Doctrine\DoctrineArrayItem
{
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
try {
$tokens->pushSavePoint();
$key = $this->parseDoctrineArrayKey($tokens);
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) {
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COLON)) {
$tokens->consumeTokenType(Lexer::TOKEN_EQUAL); // will throw exception
}
}
$value = $this->parseDoctrineArgumentValue($tokens);
$tokens->dropSavePoint();
return $this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineArrayItem($key, $value),
$startLine,
$startIndex
);
} catch (ParserException $e) {
$tokens->rollback();
return $this->enrichWithAttributes(
$tokens,
new Doctrine\DoctrineArrayItem(null, $this->parseDoctrineArgumentValue($tokens)),
$startLine,
$startIndex
);
}
}
/**
* @return ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode
*/
private function parseDoctrineArrayKey(TokenIterator $tokens)
{
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
$key = new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));
$tokens->next();
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
$key = new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($tokens->currentTokenValue()));
$tokens->next();
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
$value = $tokens->currentTokenValue();
$tokens->next();
$key = $this->doctrineConstantExprParser->parseDoctrineString($value, $tokens);
} else {
$currentTokenValue = $tokens->currentTokenValue();
$tokens->pushSavePoint(); // because of ConstFetchNode
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
$tokens->dropSavePoint();
throw new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
}
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
$tokens->dropSavePoint();
return $this->enrichWithAttributes(
$tokens,
new IdentifierTypeNode($currentTokenValue),
$startLine,
$startIndex
);
}
$tokens->rollback();
$constExpr = $this->doctrineConstantExprParser->parse($tokens, true);
if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) {
throw new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
}
return $constExpr;
}
return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);
}
/**
* @return Ast\PhpDoc\ParamTagValueNode|Ast\PhpDoc\TypelessParamTagValueNode
*/
@@ -630,15 +1127,13 @@ class PhpDocParser
{
if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
$parameter = '$this';
$requirePropertyOrMethod = true;
$tokens->next();
} else {
$parameter = $tokens->currentTokenValue();
$requirePropertyOrMethod = false;
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
}
if ($requirePropertyOrMethod || $tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {
$tokens->consumeTokenType(Lexer::TOKEN_ARROW);
$propertyOrMethod = $tokens->currentTokenValue();

View File

@@ -9,6 +9,7 @@ use function assert;
use function count;
use function in_array;
use function strlen;
use function substr;
class TokenIterator
{
@@ -22,6 +23,12 @@ class TokenIterator
/** @var int[] */
private $savePoints = [];
/** @var list<int> */
private $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
/** @var string|null */
private $newline = null;
/**
* @param list<array{string, int, int}> $tokens
*/
@@ -30,11 +37,7 @@ class TokenIterator
$this->tokens = $tokens;
$this->index = $index;
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== Lexer::TOKEN_HORIZONTAL_WS) {
return;
}
$this->index++;
$this->skipIrrelevantTokens();
}
@@ -103,6 +106,21 @@ class TokenIterator
}
public function endIndexOfLastRelevantToken(): int
{
$endIndex = $this->currentTokenIndex();
$endIndex--;
while (in_array($this->tokens[$endIndex][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) {
if (!isset($this->tokens[$endIndex - 1])) {
break;
}
$endIndex--;
}
return $endIndex;
}
public function isCurrentTokenValue(string $tokenValue): bool
{
return $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue;
@@ -130,13 +148,14 @@ class TokenIterator
$this->throwError($tokenType);
}
$this->index++;
if (($this->tokens[$this->index][Lexer::TYPE_OFFSET] ?? -1) !== Lexer::TOKEN_HORIZONTAL_WS) {
return;
if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {
if ($this->newline === null) {
$this->detectNewline();
}
}
$this->index++;
$this->skipIrrelevantTokens();
}
@@ -150,12 +169,7 @@ class TokenIterator
}
$this->index++;
if (($this->tokens[$this->index][Lexer::TYPE_OFFSET] ?? -1) !== Lexer::TOKEN_HORIZONTAL_WS) {
return;
}
$this->index++;
$this->skipIrrelevantTokens();
}
@@ -167,10 +181,7 @@ class TokenIterator
}
$this->index++;
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
$this->index++;
}
$this->skipIrrelevantTokens();
return true;
}
@@ -183,16 +194,30 @@ class TokenIterator
return false;
}
$this->index++;
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
$this->index++;
if ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {
if ($this->newline === null) {
$this->detectNewline();
}
}
$this->index++;
$this->skipIrrelevantTokens();
return true;
}
private function detectNewline(): void
{
$value = $this->currentTokenValue();
if (substr($value, 0, 2) === "\r\n") {
$this->newline = "\r\n";
} elseif (substr($value, 0, 1) === "\n") {
$this->newline = "\n";
}
}
public function getSkippedHorizontalWhiteSpaceIfAny(): string
{
if ($this->index > 0 && $this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
@@ -217,12 +242,34 @@ class TokenIterator
public function next(): void
{
$this->index++;
$this->skipIrrelevantTokens();
}
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== Lexer::TOKEN_HORIZONTAL_WS) {
private function skipIrrelevantTokens(): void
{
if (!isset($this->tokens[$this->index])) {
return;
}
$this->index++;
while (in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) {
if (!isset($this->tokens[$this->index + 1])) {
break;
}
$this->index++;
}
}
public function addEndOfLineToSkippedTokens(): void
{
$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL];
}
public function removeEndOfLineFromSkippedTokens(): void
{
$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
}
/** @phpstan-impure */
@@ -319,6 +366,11 @@ class TokenIterator
return false;
}
public function getDetectedNewline(): ?string
{
return $this->newline;
}
/**
* Whether the given position is immediately surrounded by parenthesis.
*/

View File

@@ -70,23 +70,14 @@ class TypeParser
*/
public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node
{
$endLine = $tokens->currentTokenLine();
$endIndex = $tokens->currentTokenIndex();
if ($this->useLinesAttributes) {
$type->setAttribute(Ast\Attribute::START_LINE, $startLine);
$type->setAttribute(Ast\Attribute::END_LINE, $endLine);
$type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
}
if ($this->useIndexAttributes) {
$tokensArray = $tokens->getTokens();
$endIndex--;
if ($tokensArray[$endIndex][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {
$endIndex--;
}
$type->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
$type->setAttribute(Ast\Attribute::END_INDEX, $endIndex);
$type->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
}
return $type;
@@ -205,28 +196,45 @@ class TypeParser
$tokens->dropSavePoint(); // because of ConstFetchNode
}
$exception = new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
$currentTokenValue = $tokens->currentTokenValue();
$currentTokenType = $tokens->currentTokenType();
$currentTokenOffset = $tokens->currentTokenOffset();
$currentTokenLine = $tokens->currentTokenLine();
if ($this->constExprParser === null) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
try {
$constExpr = $this->constExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex);
} catch (LogicException $e) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
}
@@ -609,23 +617,33 @@ class TypeParser
}
}
$exception = new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
$currentTokenValue = $tokens->currentTokenValue();
$currentTokenType = $tokens->currentTokenType();
$currentTokenOffset = $tokens->currentTokenOffset();
$currentTokenLine = $tokens->currentTokenLine();
if ($this->constExprParser === null) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
try {
$constExpr = $this->constExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
$type = new Ast\Type\ConstTypeNode($constExpr);
@@ -640,7 +658,14 @@ class TypeParser
return $type;
} catch (LogicException $e) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
}

View File

@@ -10,6 +10,11 @@ use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagMethodValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagPropertyValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineAnnotation;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArgument;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArray;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArrayItem;
use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ImplementsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
@@ -95,6 +100,8 @@ final class Printer
GenericTypeNode::class . '->genericTypes' => ', ',
ConstExprArrayNode::class . '->items' => ', ',
MethodTagValueNode::class . '->parameters' => ', ',
DoctrineArray::class . '->items' => ', ',
DoctrineAnnotation::class . '->arguments' => ', ',
];
/**
@@ -106,6 +113,8 @@ final class Printer
CallableTypeNode::class . '->parameters' => ['(', '', ''],
ArrayShapeNode::class . '->items' => ['{', '', ''],
ObjectShapeNode::class . '->items' => ['{', '', ''],
DoctrineArray::class . '->items' => ['{', '', ''],
DoctrineAnnotation::class . '->arguments' => ['(', '', ''],
];
/** @var array<string, list<class-string<TypeNode>>> */
@@ -186,6 +195,10 @@ final class Printer
return $node->text;
}
if ($node instanceof PhpDocTagNode) {
if ($node->value instanceof DoctrineTagValueNode) {
return $this->print($node->value);
}
return trim(sprintf('%s %s', $node->name, $this->print($node->value)));
}
if ($node instanceof PhpDocTagValueNode) {
@@ -211,6 +224,18 @@ final class Printer
$isOptional = $node->isOptional ? '=' : '';
return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional;
}
if ($node instanceof DoctrineAnnotation) {
return (string) $node;
}
if ($node instanceof DoctrineArgument) {
return (string) $node;
}
if ($node instanceof DoctrineArray) {
return (string) $node;
}
if ($node instanceof DoctrineArrayItem) {
return (string) $node;
}
throw new LogicException(sprintf('Unknown node type %s', get_class($node)));
}
@@ -491,7 +516,7 @@ final class Printer
[$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens);
if ($insertStr === "\n * ") {
$insertStr = sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent);
$insertStr = sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
}
foreach ($diff as $i => $diffElem) {
@@ -524,7 +549,7 @@ final class Printer
}
if ($insertNewline) {
$result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent);
$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
} else {
$result .= $insertStr;
}
@@ -568,7 +593,7 @@ final class Printer
$itemEndPos = $tokenIndex - 1;
if ($insertNewline) {
$result .= $insertStr . sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent);
$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
} else {
$result .= $insertStr;
}
@@ -637,7 +662,7 @@ final class Printer
if (!$first) {
$result .= $insertStr;
if ($insertNewline) {
$result .= sprintf("\n%s*%s", $beforeAsteriskIndent, $afterAsteriskIndent);
$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
}
}

Binary file not shown.

View File

@@ -1,16 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmRaZmcACgkQUcZzBf/C
5cAn/Q//fbWiR/qaSvlHpk73KH7iDfoHwNvRrHSQODZdMa4PGiEbL+SXsKnRxFDo
kEJZwgU5qi3WMflt7Ml3dYDlQDgoDerdaiySYFoBcv1NXDWKoF7+Egy1AHxpfNq+
FMCkZNR2ulSaYUCofM4GkTNap4yVkPCy289ZU6yUmRnJxF+hh/CFfdVPAPbwh/a6
UqV3R2ENJZSbtA1pzSTBpUPQGQ9qcsqngKyNyxk1hEd9opdMg2eSFvO1e1ZZm/Tk
Kgh5wCbsbSJuRPGO4vbiybTeO/qXPDlHV6oA5SHnjJ4H24phCsHdyJHHvLQmrUeR
BKHgnH1y/b5J9cgr9OgEQJK9TMHHd6dii9//Qp+0rUZIDZ4Ym2lDSA/Vn/D9GoV3
zo4QYzW3TvE3QMdnLcX/ZtaLliPdDYIaYUXOiyaYwLFGVxSWZWOC5IN0G0bLJb39
Ca/z839nkWdMqg68q/oHC2Nk/v/KZnKg1RlRjYhj53T6nr0JDEiaYMyETSOIFsVX
AcCQnLLwMndUAibJAyORDnTk+ipg0SecFoPvvhea1BtlTfhSDIlrT4OPKZ5nExzd
nR/zGbIH8lCvsBc+hq+Kgodtfs5nauwEOwlVUwet26xL1YKOd0jxz+Zp6tgk0wba
cMf5L9fm85j83DQYr7Ukaaj81kmMujRWDo/dRojKhUlJUrNnjXA=
=jTtX
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmUBhZwACgkQUcZzBf/C
5cDAIA/+JOxOdWCg6b1+/Bs4Opm7cmILJzh3Rw1366MzXFHJhe2n7exemzTE3X2E
0HTjVVWoE0MpTt6knBgb+dulXTGm+yzJNIRLnCJFhsSdwUcxNAZMPozliZszGMcC
HhGC1Ya7RU5d9WEg/lCAKRjNgSeY8VTRRfa49m6TQPQwGinXBNpH6q665feziUX5
NB+rBMaWUDKp6GelPVrezEfME+SMfT66hW31n5m5paTwT+khk2Cenub5xXBUyXtz
saxSayOShlUPN8kZKOjS/L/FPnOApGwcKxkX2kMK0qDs8YQFYHibNgnyhrEOBRD1
UV9kBiU1+LUuxDcya8f0qo/gk6QN7Y/ywnIY3kTkqTYchCAAO+osu1amLYlInBSu
r0LtQQ8+/llQ/bP0XS6cC6247J1fxO9xYMMmKVBfJrul3Wi6ETRI5WIdEQTSc2Z+
rE00JY2X/vxJijUyGZ88+QDX3z7vGyaQJZiXq1XyjmBYw6w8UlxhGZcGGDIbTsb7
lACLR/t4hgtE69QXW+L4P2ngU0agk5XXojg/+r+CnCWD/TdKcvs1WTn4TyuMZOLa
2XF3h9/H0XMfE5LPlNJmb4YRjYjcNvPQwmGI4dmUMCJuTpjHUnpFXfswu4xgsaYV
xq756DVfrRyG9PyXFfJZ66P7jt5+wisrVsWh/X3nX69P0ruwwss=
=aOCq
-----END PGP SIGNATURE-----

View File

@@ -2,6 +2,23 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [9.2.28] - 2023-09-12
### Changed
* [#1011](https://github.com/sebastianbergmann/php-code-coverage/pull/1011): Avoid serialization of cache data in PHP report
## [9.2.27] - 2023-07-26
### Changed
* The result of `CodeCoverage::getReport()` is now cached
### Fixed
* Static analysis cache keys do not include configuration settings that affect source code parsing
* The Clover, Cobertura, Crap4j, and PHP report writers no longer create a `php:` directory when they should write to `php://stdout`, for instance
## [9.2.26] - 2023-03-06
### Changed
@@ -476,6 +493,8 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* This component is no longer supported on PHP 7.1
[9.2.28]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.27...9.2.28
[9.2.27]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.26...9.2.27
[9.2.26]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.25...9.2.26
[9.2.25]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.24...9.2.25
[9.2.24]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.23...9.2.24

View File

@@ -17,7 +17,8 @@
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues"
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy"
},
"config": {
"platform": {

View File

@@ -114,6 +114,11 @@ final class CodeCoverage
*/
private $cacheDirectory;
/**
* @var ?Directory
*/
private $cachedReport;
public function __construct(Driver $driver, Filter $filter)
{
$this->driver = $driver;
@@ -127,7 +132,11 @@ final class CodeCoverage
*/
public function getReport(): Directory
{
return (new Builder($this->analyser()))->build($this);
if ($this->cachedReport === null) {
$this->cachedReport = (new Builder($this->analyser()))->build($this);
}
return $this->cachedReport;
}
/**
@@ -135,9 +144,18 @@ final class CodeCoverage
*/
public function clear(): void
{
$this->currentId = null;
$this->data = new ProcessedCodeCoverageData;
$this->tests = [];
$this->currentId = null;
$this->data = new ProcessedCodeCoverageData;
$this->tests = [];
$this->cachedReport = null;
}
/**
* @internal
*/
public function clearCache(): void
{
$this->cachedReport = null;
}
/**
@@ -202,6 +220,8 @@ final class CodeCoverage
$this->currentId = $id;
$this->driver->start();
$this->cachedReport = null;
}
/**
@@ -220,7 +240,8 @@ final class CodeCoverage
$data = $this->driver->stop();
$this->append($data, null, $append, $linesToBeCovered, $linesToBeUsed);
$this->currentId = null;
$this->currentId = null;
$this->cachedReport = null;
return $data;
}
@@ -245,6 +266,8 @@ final class CodeCoverage
throw new TestIdMissingException;
}
$this->cachedReport = null;
$this->applyFilter($rawData);
$this->applyExecutableLinesFilter($rawData);
@@ -312,6 +335,8 @@ final class CodeCoverage
$this->data->merge($that->data);
$this->tests = array_merge($this->tests, $that->getTests());
$this->cachedReport = null;
}
public function enableCheckForUnintentionallyCoveredCode(): void
@@ -673,7 +698,9 @@ final class CodeCoverage
if ($this->cachesStaticAnalysis()) {
$this->analyser = new CachingFileAnalyser(
$this->cacheDirectory,
$this->analyser
$this->analyser,
$this->useAnnotationsForIgnoringCode,
$this->ignoreDeprecatedCode
);
}

View File

@@ -16,6 +16,7 @@ use function is_string;
use function ksort;
use function max;
use function range;
use function strpos;
use function time;
use DOMDocument;
use SebastianBergmann\CodeCoverage\CodeCoverage;
@@ -243,7 +244,9 @@ final class Clover
$buffer = $xmlDocument->saveXML();
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -16,6 +16,7 @@ use function file_put_contents;
use function preg_match;
use function range;
use function str_replace;
use function strpos;
use function time;
use DOMImplementation;
use SebastianBergmann\CodeCoverage\CodeCoverage;
@@ -294,7 +295,9 @@ final class Cobertura
$buffer = $document->saveXML();
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -15,6 +15,7 @@ use function file_put_contents;
use function htmlspecialchars;
use function is_string;
use function round;
use function strpos;
use DOMDocument;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
@@ -124,7 +125,9 @@ final class Crap4j
$buffer = $document->saveXML();
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -12,6 +12,7 @@ namespace SebastianBergmann\CodeCoverage\Report;
use function dirname;
use function file_put_contents;
use function serialize;
use function strpos;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
@@ -20,11 +21,15 @@ final class PHP
{
public function process(CodeCoverage $coverage, ?string $target = null): string
{
$coverage->clearCache();
$buffer = "<?php
return \unserialize(<<<'END_OF_COVERAGE_SERIALIZATION'" . PHP_EOL . serialize($coverage) . PHP_EOL . 'END_OF_COVERAGE_SERIALIZATION' . PHP_EOL . ');';
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -17,7 +17,6 @@ use DOMElement;
final class Tests
{
private $contextNode;
private $codeMap = [
-1 => 'UNKNOWN', // PHPUnit_Runner_BaseTestRunner::STATUS_UNKNOWN
0 => 'PASSED', // PHPUnit_Runner_BaseTestRunner::STATUS_PASSED

View File

@@ -20,7 +20,9 @@ final class CacheWarmer
new ParsingFileAnalyser(
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode
)
),
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode,
);
foreach ($filter->files() as $file) {

View File

@@ -29,27 +29,39 @@ final class CachingFileAnalyser implements FileAnalyser
*/
private static $cacheVersion;
/**
* @var string
*/
private $directory;
/**
* @var FileAnalyser
*/
private $analyser;
/**
* @var bool
*/
private $useAnnotationsForIgnoringCode;
/**
* @var bool
*/
private $ignoreDeprecatedCode;
/**
* @var array
*/
private $cache = [];
/**
* @var string
*/
private $directory;
public function __construct(string $directory, FileAnalyser $analyser)
public function __construct(string $directory, FileAnalyser $analyser, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode)
{
Filesystem::createDirectory($directory);
$this->analyser = $analyser;
$this->directory = $directory;
$this->analyser = $analyser;
$this->directory = $directory;
$this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode;
$this->ignoreDeprecatedCode = $ignoreDeprecatedCode;
}
public function classesIn(string $filename): array
@@ -161,7 +173,20 @@ final class CachingFileAnalyser implements FileAnalyser
private function cacheFile(string $filename): string
{
return $this->directory . DIRECTORY_SEPARATOR . md5($filename . "\0" . file_get_contents($filename) . "\0" . self::cacheVersion());
$cacheKey = md5(
implode(
"\0",
[
$filename,
file_get_contents($filename),
self::cacheVersion(),
$this->useAnnotationsForIgnoringCode,
$this->ignoreDeprecatedCode,
]
)
);
return $this->directory . DIRECTORY_SEPARATOR . $cacheKey;
}
private static function cacheVersion(): string

View File

@@ -101,6 +101,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
$node instanceof Node\Stmt\Else_ ||
$node instanceof Node\Stmt\EnumCase ||
$node instanceof Node\Stmt\Finally_ ||
$node instanceof Node\Stmt\GroupUse ||
$node instanceof Node\Stmt\Label ||
$node instanceof Node\Stmt\Namespace_ ||
$node instanceof Node\Stmt\Nop ||

View File

@@ -22,7 +22,7 @@ final class Version
public static function id(): string
{
if (self::$version === null) {
self::$version = (new VersionId('9.2.26', dirname(__DIR__)))->getVersion();
self::$version = (new VersionId('9.2.28', dirname(__DIR__)))->getVersion();
}
return self::$version;

View File

@@ -2,6 +2,31 @@
All notable changes of the PHPUnit 9.6 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [9.6.12] - 2023-09-12
### Changed
* [#5508](https://github.com/sebastianbergmann/phpunit/pull/5508): Generate code coverage report in PHP format as first in list to avoid serializing cache data
## [9.6.11] - 2023-08-19
### Added
* [#5478](https://github.com/sebastianbergmann/phpunit/pull/5478): `assertObjectHasProperty()` and `assertObjectNotHasProperty()`
## [9.6.10] - 2023-07-10
### Changed
* [#5419](https://github.com/sebastianbergmann/phpunit/pull/5419): Allow empty `<extensions>` element in XML configuration
## [9.6.9] - 2023-06-11
### Fixed
* [#5405](https://github.com/sebastianbergmann/phpunit/issues/5405): XML configuration migration does not migrate `whitelist/file` elements
* Always use `X.Y.Z` version number (and not just `X.Y`) of PHPUnit's version when checking whether a PHAR-distributed extension is compatible
## [9.6.8] - 2023-05-11
### Fixed
@@ -64,6 +89,10 @@ All notable changes of the PHPUnit 9.6 release series are documented in this fil
* [#5064](https://github.com/sebastianbergmann/phpunit/issues/5064): Deprecate `PHPUnit\Framework\TestCase::getMockClass()`
* [#5132](https://github.com/sebastianbergmann/phpunit/issues/5132): Deprecate `Test` suffix for abstract test case classes
[9.6.12]: https://github.com/sebastianbergmann/phpunit/compare/9.6.11...9.6.12
[9.6.11]: https://github.com/sebastianbergmann/phpunit/compare/9.6.10...9.6.11
[9.6.10]: https://github.com/sebastianbergmann/phpunit/compare/9.6.9...9.6.10
[9.6.9]: https://github.com/sebastianbergmann/phpunit/compare/9.6.8...9.6.9
[9.6.8]: https://github.com/sebastianbergmann/phpunit/compare/9.6.7...9.6.8
[9.6.7]: https://github.com/sebastianbergmann/phpunit/compare/9.6.6...9.6.7
[9.6.6]: https://github.com/sebastianbergmann/phpunit/compare/9.6.5...9.6.6

89
vendor/phpunit/phpunit/DEPRECATIONS.md vendored Normal file
View File

@@ -0,0 +1,89 @@
# Deprecations
## Soft Deprecations
This functionality is currently [soft-deprecated](https://phpunit.de/backward-compatibility.html#soft-deprecation):
### Writing Tests
#### Test Double API
| Issue | Description | Since | Replacement |
|-------------------------------------------------------------------|-----------------------------------|-------|-------------|
| [#3687](https://github.com/sebastianbergmann/phpunit/issues/3687) | `MockBuilder::setMethods()` | 8.3.0 | |
| [#3687](https://github.com/sebastianbergmann/phpunit/issues/3687) | `MockBuilder::setMethodsExcept()` | 9.6.0 | |
## Hard Deprecations
This functionality is currently [hard-deprecated](https://phpunit.de/backward-compatibility.html#hard-deprecation):
### Writing Tests
#### Assertions, Constraints, and Expectations
| Issue | Description | Since | Replacement |
|-------------------------------------------------------------------|------------------------------------------------|-------|---------------------------------------------------|
| [#4062](https://github.com/sebastianbergmann/phpunit/issues/4062) | `TestCase::assertNotIsReadable()` | 9.1.0 | `TestCase::assertIsNotReadable()` |
| [#4065](https://github.com/sebastianbergmann/phpunit/issues/4065) | `TestCase::assertNotIsWritable()` | 9.1.0 | `TestCase::assertIsNotWritable()` |
| [#4068](https://github.com/sebastianbergmann/phpunit/issues/4068) | `TestCase::assertDirectoryNotExists()` | 9.1.0 | `TestCase::assertDirectoryDoesNotExist()` |
| [#4071](https://github.com/sebastianbergmann/phpunit/issues/4071) | `TestCase::assertDirectoryNotIsReadable()` | 9.1.0 | `TestCase::assertDirectoryIsNotReadable()` |
| [#4074](https://github.com/sebastianbergmann/phpunit/issues/4074) | `TestCase::assertDirectoryNotIsWritable()` | 9.1.0 | `TestCase::assertDirectoryIsNotWritable()` |
| [#4077](https://github.com/sebastianbergmann/phpunit/issues/4077) | `TestCase::assertFileNotExists()` | 9.1.0 | `TestCase::assertFileDoesNotExist()` |
| [#4080](https://github.com/sebastianbergmann/phpunit/issues/4080) | `TestCase::assertFileNotIsReadable()` | 9.1.0 | `TestCase::assertFileIsNotReadable()` |
| [#4083](https://github.com/sebastianbergmann/phpunit/issues/4083) | `TestCase::assertFileNotIsWritable()` | 9.1.0 | `TestCase::assertFileIsNotWritable()` |
| [#4086](https://github.com/sebastianbergmann/phpunit/issues/4086) | `TestCase::assertRegExp()` | 9.1.0 | `TestCase::assertMatchesRegularExpression()` |
| [#4089](https://github.com/sebastianbergmann/phpunit/issues/4089) | `TestCase::assertNotRegExp()` | 9.1.0 | `TestCase::assertDoesNotMatchRegularExpression()` |
| [#4091](https://github.com/sebastianbergmann/phpunit/issues/4091) | `TestCase::assertEqualXMLStructure()` | 9.1.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectDeprecation()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectDeprecationMessage()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectDeprecationMessageMatches()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectError()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectErrorMessage()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectErrorMessageMatches()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectNotice()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectNoticeMessage()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectNoticeMessageMatches()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectWarning()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectWarningMessage()` | 9.6.0 | |
| [#5062](https://github.com/sebastianbergmann/phpunit/issues/5062) | `TestCase::expectWarningMessageMatches()` | 9.6.0 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::assertClassHasAttribute()` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::assertClassNotHasAttribute()` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::assertClassHasStaticAttribute()` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::assertClassNotHasStaticAttribute()` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::assertObjectHasAttribute()` | 9.6.1 | `TestCase::assertObjectHasProperty()` |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::assertObjectNotHasAttribute()` | 9.6.1 | `TestCase::assertObjectNotHasProperty()` |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::classHasAttribute()` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::classHasStaticAttribute()` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `TestCase::objectHasAttribute()` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `ClassHasAttribute` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `ClassHasStaticAttribute` | 9.6.1 | |
| [#4601](https://github.com/sebastianbergmann/phpunit/issues/4601) | `ObjectHasAttribute` | 9.6.1 | `ObjectHasProperty` |
#### Test Double API
| Issue | Description | Since | Replacement |
|-------------------------------------------------------------------|---------------------------------------|-------|-------------------------------------------------------------------------|
| [#4141](https://github.com/sebastianbergmann/phpunit/issues/4141) | `TestCase::prophesize()` | 9.1.0 | [phpspec/prophecy-phpunit](https://github.com/phpspec/prophecy-phpunit) |
| [#4297](https://github.com/sebastianbergmann/phpunit/issues/4297) | `TestCase::at()` | 9.3.0 | |
| [#4297](https://github.com/sebastianbergmann/phpunit/issues/4297) | `InvokedAtIndex` | 9.3.0 | |
| [#5063](https://github.com/sebastianbergmann/phpunit/issues/5063) | `InvocationMocker::withConsecutive()` | 9.6.0 | |
| [#5063](https://github.com/sebastianbergmann/phpunit/issues/5063) | `ConsecutiveParameters` | 9.6.0 | |
| [#5064](https://github.com/sebastianbergmann/phpunit/issues/5064) | `TestCase::getMockClass()` | 9.6.0 | |
#### Miscellaneous
| Issue | Description | Since | Replacement |
|-------------------------------------------------------------------|----------------------------------------------|-------|------------------------------------------------|
| [#5132](https://github.com/sebastianbergmann/phpunit/issues/5132) | `Test` suffix for abstract test case classes | | |
| | `TestCase::$backupGlobalsBlacklist` | 9.3.0 | `TestCase::$backupGlobalsExcludeList` |
| | `TestCase::$backupStaticAttributesBlacklist` | 9.3.0 | `TestCase::$backupStaticAttributesExcludeList` |
### Extending PHPUnit
| Issue | Description | Since | Replacement |
|-------------------------------------------------------------------|--------------------------------------|-------|-------------------------------------------------------------|
| [#4676](https://github.com/sebastianbergmann/phpunit/issues/4676) | `TestListener` | 8.0.0 | [Event System](https://docs.phpunit.de/en/10.3/events.html) |
| [#4039](https://github.com/sebastianbergmann/phpunit/issues/4039) | `Command::handleLoader()` | 9.1.0 | |
| [#4039](https://github.com/sebastianbergmann/phpunit/issues/4039) | `TestSuiteLoader` | 9.1.0 | |
| [#4039](https://github.com/sebastianbergmann/phpunit/issues/4039) | `StandardTestSuiteLoader` | 9.1.0 | |
| [#4676](https://github.com/sebastianbergmann/phpunit/issues/4676) | `TestListenerDefaultImplementation` | 8.2.4 | [Event System](https://docs.phpunit.de/en/10.3/events.html) |

View File

@@ -25,7 +25,7 @@ Alternatively, you may use [Composer](https://getcomposer.org/) to download and
## Contribute
Please refer to [CONTRIBUTING.md](https://github.com/sebastianbergmann/phpunit/blob/master/.github/CONTRIBUTING.md) for information on how to contribute to PHPUnit and its related projects.
Please refer to [CONTRIBUTING.md](https://github.com/sebastianbergmann/phpunit/blob/main/.github/CONTRIBUTING.md) for information on how to contribute to PHPUnit and its related projects.
## List of Contributors

View File

@@ -33,7 +33,7 @@
"myclabs/deep-copy": "^1.10.1",
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-code-coverage": "^9.2.28",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",

View File

@@ -57,7 +57,7 @@
</xs:complexType>
<xs:complexType name="extensionsType">
<xs:sequence>
<xs:element name="extension" type="objectType" maxOccurs="unbounded"/>
<xs:element name="extension" type="objectType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="listenersType">

View File

@@ -73,6 +73,7 @@ use PHPUnit\Framework\Constraint\LogicalOr;
use PHPUnit\Framework\Constraint\LogicalXor;
use PHPUnit\Framework\Constraint\ObjectEquals;
use PHPUnit\Framework\Constraint\ObjectHasAttribute;
use PHPUnit\Framework\Constraint\ObjectHasProperty;
use PHPUnit\Framework\Constraint\RegularExpression;
use PHPUnit\Framework\Constraint\SameSize;
use PHPUnit\Framework\Constraint\StringContains;
@@ -111,14 +112,14 @@ abstract class Assert
if (!(is_int($key) || is_string($key))) {
throw InvalidArgumentException::create(
1,
'integer or string'
'integer or string',
);
}
if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
2,
'array or ArrayAccess'
'array or ArrayAccess',
);
}
@@ -142,19 +143,19 @@ abstract class Assert
if (!(is_int($key) || is_string($key))) {
throw InvalidArgumentException::create(
1,
'integer or string'
'integer or string',
);
}
if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
2,
'array or ArrayAccess'
'array or ArrayAccess',
);
}
$constraint = new LogicalNot(
new ArrayHasKey($key)
new ArrayHasKey($key),
);
static::assertThat($array, $constraint, $message);
@@ -191,7 +192,7 @@ abstract class Assert
public static function assertNotContains($needle, iterable $haystack, string $message = ''): void
{
$constraint = new LogicalNot(
new TraversableContainsIdentical($needle)
new TraversableContainsIdentical($needle),
);
static::assertThat($haystack, $constraint, $message);
@@ -220,9 +221,9 @@ abstract class Assert
$haystack,
new TraversableContainsOnly(
$type,
$isNativeType
$isNativeType,
),
$message
$message,
);
}
@@ -238,9 +239,9 @@ abstract class Assert
$haystack,
new TraversableContainsOnly(
$className,
false
false,
),
$message
$message,
);
}
@@ -261,10 +262,10 @@ abstract class Assert
new LogicalNot(
new TraversableContainsOnly(
$type,
$isNativeType
)
$isNativeType,
),
),
$message
$message,
);
}
@@ -290,7 +291,7 @@ abstract class Assert
static::assertThat(
$haystack,
new Count($expectedCount),
$message
$message,
);
}
@@ -314,7 +315,7 @@ abstract class Assert
}
$constraint = new LogicalNot(
new Count($expectedCount)
new Count($expectedCount),
);
static::assertThat($haystack, $constraint, $message);
@@ -369,7 +370,7 @@ abstract class Assert
{
$constraint = new IsEqualWithDelta(
$expected,
$delta
$delta,
);
static::assertThat($actual, $constraint, $message);
@@ -384,7 +385,7 @@ abstract class Assert
public static function assertNotEquals($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqual($expected)
new IsEqual($expected),
);
static::assertThat($actual, $constraint, $message);
@@ -399,7 +400,7 @@ abstract class Assert
public static function assertNotEqualsCanonicalizing($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqualCanonicalizing($expected)
new IsEqualCanonicalizing($expected),
);
static::assertThat($actual, $constraint, $message);
@@ -414,7 +415,7 @@ abstract class Assert
public static function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqualIgnoringCase($expected)
new IsEqualIgnoringCase($expected),
);
static::assertThat($actual, $constraint, $message);
@@ -431,8 +432,8 @@ abstract class Assert
$constraint = new LogicalNot(
new IsEqualWithDelta(
$expected,
$delta
)
$delta,
),
);
static::assertThat($actual, $constraint, $message);
@@ -446,7 +447,7 @@ abstract class Assert
static::assertThat(
$actual,
static::objectEquals($expected, $method),
$message
$message,
);
}
@@ -506,7 +507,7 @@ abstract class Assert
static::assertThat(
$actual,
static::greaterThanOrEqual($expected),
$message
$message,
);
}
@@ -562,7 +563,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new IsEqualCanonicalizing(
file_get_contents($expected)
file_get_contents($expected),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -598,7 +599,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new LogicalNot(
new IsEqual(file_get_contents($expected))
new IsEqual(file_get_contents($expected)),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -617,7 +618,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new LogicalNot(
new IsEqualCanonicalizing(file_get_contents($expected))
new IsEqualCanonicalizing(file_get_contents($expected)),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -636,7 +637,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new LogicalNot(
new IsEqualIgnoringCase(file_get_contents($expected))
new IsEqualIgnoringCase(file_get_contents($expected)),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -702,7 +703,7 @@ abstract class Assert
static::assertFileExists($expectedFile, $message);
$constraint = new LogicalNot(
new IsEqual(file_get_contents($expectedFile))
new IsEqual(file_get_contents($expectedFile)),
);
static::assertThat($actualString, $constraint, $message);
@@ -720,7 +721,7 @@ abstract class Assert
static::assertFileExists($expectedFile, $message);
$constraint = new LogicalNot(
new IsEqualCanonicalizing(file_get_contents($expectedFile))
new IsEqualCanonicalizing(file_get_contents($expectedFile)),
);
static::assertThat($actualString, $constraint, $message);
@@ -738,7 +739,7 @@ abstract class Assert
static::assertFileExists($expectedFile, $message);
$constraint = new LogicalNot(
new IsEqualIgnoringCase(file_get_contents($expectedFile))
new IsEqualIgnoringCase(file_get_contents($expectedFile)),
);
static::assertThat($actualString, $constraint, $message);
@@ -1227,9 +1228,9 @@ abstract class Assert
static::assertThat(
$className,
new LogicalNot(
new ClassHasAttribute($attributeName)
new ClassHasAttribute($attributeName),
),
$message
$message,
);
}
@@ -1257,7 +1258,7 @@ abstract class Assert
static::assertThat(
$className,
new ClassHasStaticAttribute($attributeName),
$message
$message,
);
}
@@ -1285,9 +1286,9 @@ abstract class Assert
static::assertThat(
$className,
new LogicalNot(
new ClassHasStaticAttribute($attributeName)
new ClassHasStaticAttribute($attributeName),
),
$message
$message,
);
}
@@ -1304,7 +1305,7 @@ abstract class Assert
*/
public static function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void
{
self::createWarning('assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectHasProperty() (PHPUnit 10.1.0+) instead.');
self::createWarning('assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectHasProperty() instead.');
if (!self::isValidObjectAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
@@ -1317,7 +1318,7 @@ abstract class Assert
static::assertThat(
$object,
new ObjectHasAttribute($attributeName),
$message
$message,
);
}
@@ -1334,7 +1335,7 @@ abstract class Assert
*/
public static function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void
{
self::createWarning('assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectNotHasProperty() (PHPUnit 10.1.0+) instead.');
self::createWarning('assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectNotHasProperty() instead.');
if (!self::isValidObjectAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
@@ -1347,9 +1348,39 @@ abstract class Assert
static::assertThat(
$object,
new LogicalNot(
new ObjectHasAttribute($attributeName)
new ObjectHasAttribute($attributeName),
),
$message
$message,
);
}
/**
* Asserts that an object has a specified property.
*
* @throws ExpectationFailedException
*/
final public static function assertObjectHasProperty(string $propertyName, object $object, string $message = ''): void
{
static::assertThat(
$object,
new ObjectHasProperty($propertyName),
$message,
);
}
/**
* Asserts that an object does not have a specified property.
*
* @throws ExpectationFailedException
*/
final public static function assertObjectNotHasProperty(string $propertyName, object $object, string $message = ''): void
{
static::assertThat(
$object,
new LogicalNot(
new ObjectHasProperty($propertyName),
),
$message,
);
}
@@ -1372,7 +1403,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsIdentical($expected),
$message
$message,
);
}
@@ -1393,9 +1424,9 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(
new IsIdentical($expected)
new IsIdentical($expected),
),
$message
$message,
);
}
@@ -1421,7 +1452,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsInstanceOf($expected),
$message
$message,
);
}
@@ -1447,9 +1478,9 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(
new IsInstanceOf($expected)
new IsInstanceOf($expected),
),
$message
$message,
);
}
@@ -1466,7 +1497,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_ARRAY),
$message
$message,
);
}
@@ -1483,7 +1514,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_BOOL),
$message
$message,
);
}
@@ -1500,7 +1531,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_FLOAT),
$message
$message,
);
}
@@ -1517,7 +1548,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_INT),
$message
$message,
);
}
@@ -1534,7 +1565,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_NUMERIC),
$message
$message,
);
}
@@ -1551,7 +1582,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_OBJECT),
$message
$message,
);
}
@@ -1568,7 +1599,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_RESOURCE),
$message
$message,
);
}
@@ -1585,7 +1616,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_CLOSED_RESOURCE),
$message
$message,
);
}
@@ -1602,7 +1633,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_STRING),
$message
$message,
);
}
@@ -1619,7 +1650,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_SCALAR),
$message
$message,
);
}
@@ -1636,7 +1667,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_CALLABLE),
$message
$message,
);
}
@@ -1653,7 +1684,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_ITERABLE),
$message
$message,
);
}
@@ -1670,7 +1701,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_ARRAY)),
$message
$message,
);
}
@@ -1687,7 +1718,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_BOOL)),
$message
$message,
);
}
@@ -1704,7 +1735,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_FLOAT)),
$message
$message,
);
}
@@ -1721,7 +1752,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_INT)),
$message
$message,
);
}
@@ -1738,7 +1769,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_NUMERIC)),
$message
$message,
);
}
@@ -1755,7 +1786,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_OBJECT)),
$message
$message,
);
}
@@ -1772,7 +1803,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_RESOURCE)),
$message
$message,
);
}
@@ -1789,7 +1820,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_CLOSED_RESOURCE)),
$message
$message,
);
}
@@ -1806,7 +1837,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_STRING)),
$message
$message,
);
}
@@ -1823,7 +1854,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_SCALAR)),
$message
$message,
);
}
@@ -1840,7 +1871,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_CALLABLE)),
$message
$message,
);
}
@@ -1857,7 +1888,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_ITERABLE)),
$message
$message,
);
}
@@ -1900,9 +1931,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new RegularExpression($pattern)
new RegularExpression($pattern),
),
$message
$message,
);
}
@@ -1923,9 +1954,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new RegularExpression($pattern)
new RegularExpression($pattern),
),
$message
$message,
);
}
@@ -1961,7 +1992,7 @@ abstract class Assert
static::assertThat(
$actual,
new SameSize($expected),
$message
$message,
);
}
@@ -1997,9 +2028,9 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(
new SameSize($expected)
new SameSize($expected),
),
$message
$message,
);
}
@@ -2025,9 +2056,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new StringMatchesFormatDescription($format)
new StringMatchesFormatDescription($format),
),
$message
$message,
);
}
@@ -2044,9 +2075,9 @@ abstract class Assert
static::assertThat(
$string,
new StringMatchesFormatDescription(
file_get_contents($formatFile)
file_get_contents($formatFile),
),
$message
$message,
);
}
@@ -2064,10 +2095,10 @@ abstract class Assert
$string,
new LogicalNot(
new StringMatchesFormatDescription(
file_get_contents($formatFile)
)
file_get_contents($formatFile),
),
),
$message
$message,
);
}
@@ -2096,9 +2127,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new StringStartsWith($prefix)
new StringStartsWith($prefix),
),
$message
$message,
);
}
@@ -2168,9 +2199,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new StringEndsWith($suffix)
new StringEndsWith($suffix),
),
$message
$message,
);
}
@@ -2335,7 +2366,7 @@ abstract class Assert
static::assertSame(
$expectedElement->tagName,
$actualElement->tagName,
$message
$message,
);
if ($checkAttributes) {
@@ -2346,8 +2377,8 @@ abstract class Assert
'%s%sNumber of attributes on node "%s" does not match',
$message,
!empty($message) ? "\n" : '',
$expectedElement->tagName
)
$expectedElement->tagName,
),
);
for ($i = 0; $i < $expectedElement->attributes->length; $i++) {
@@ -2363,8 +2394,8 @@ abstract class Assert
$message,
!empty($message) ? "\n" : '',
$expectedAttribute->name,
$expectedElement->tagName
)
$expectedElement->tagName,
),
);
}
}
@@ -2380,8 +2411,8 @@ abstract class Assert
'%s%sNumber of child nodes of "%s" differs',
$message,
!empty($message) ? "\n" : '',
$expectedElement->tagName
)
$expectedElement->tagName,
),
);
for ($i = 0; $i < $expectedElement->childNodes->length; $i++) {
@@ -2389,7 +2420,7 @@ abstract class Assert
$expectedElement->childNodes->item($i),
$actualElement->childNodes->item($i),
$checkAttributes,
$message
$message,
);
}
}
@@ -2449,9 +2480,9 @@ abstract class Assert
static::assertThat(
$actualJson,
new LogicalNot(
new JsonMatches($expectedJson)
new JsonMatches($expectedJson),
),
$message
$message,
);
}
@@ -2489,9 +2520,9 @@ abstract class Assert
static::assertThat(
$actualJson,
new LogicalNot(
new JsonMatches($expectedJson)
new JsonMatches($expectedJson),
),
$message
$message,
);
}
@@ -2513,7 +2544,7 @@ abstract class Assert
static::assertJson($actualJson, $message);
$constraintExpected = new JsonMatches(
$expectedJson
$expectedJson,
);
$constraintActual = new JsonMatches($actualJson);
@@ -2540,7 +2571,7 @@ abstract class Assert
static::assertJson($actualJson, $message);
$constraintExpected = new JsonMatches(
$expectedJson
$expectedJson,
);
$constraintActual = new JsonMatches($actualJson);
@@ -2721,7 +2752,7 @@ abstract class Assert
{
return static::logicalOr(
new IsEqual($value),
new GreaterThan($value)
new GreaterThan($value),
);
}
@@ -2779,7 +2810,7 @@ abstract class Assert
{
return static::logicalOr(
new IsEqual($value),
new LessThan($value)
new LessThan($value),
);
}

View File

@@ -1444,6 +1444,42 @@ if (!function_exists('PHPUnit\Framework\assertObjectNotHasAttribute')) {
}
}
if (!function_exists('PHPUnit\Framework\assertObjectHasProperty')) {
/**
* Asserts that an object has a specified property.
*
* @throws ExpectationFailedException
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see Assert::assertObjectHasProperty
*/
function assertObjectHasProperty(string $attributeName, object $object, string $message = ''): void
{
Assert::assertObjectHasProperty(...func_get_args());
}
}
if (!function_exists('PHPUnit\Framework\assertObjectNotHasProperty')) {
/**
* Asserts that an object does not have a specified property.
*
* @throws ExpectationFailedException
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see Assert::assertObjectNotHasProperty
*/
function assertObjectNotHasProperty(string $attributeName, object $object, string $message = ''): void
{
Assert::assertObjectNotHasProperty(...func_get_args());
}
}
if (!function_exists('PHPUnit\Framework\assertSame')) {
/**
* Asserts that two variables have the same type and value.
@@ -2927,7 +2963,7 @@ if (!function_exists('PHPUnit\Framework\atLeast')) {
function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher
{
return new InvokedAtLeastCountMatcher(
$requiredInvocations
$requiredInvocations,
);
}
}

View File

@@ -40,7 +40,7 @@ class Count extends Constraint
{
return sprintf(
'count matches %d',
$this->expectedCount
$this->expectedCount,
);
}
@@ -76,7 +76,7 @@ class Count extends Constraint
throw new Exception(
$e->getMessage(),
$e->getCode(),
$e
$e,
);
}
}
@@ -136,7 +136,7 @@ class Count extends Constraint
return sprintf(
'actual size %d matches expected size %d',
(int) $this->getCountOf($other),
$this->expectedCount
$this->expectedCount,
);
}
}

View File

@@ -64,7 +64,7 @@ final class IsEmpty extends Constraint
'%s %s %s',
strpos($type, 'a') === 0 || strpos($type, 'o') === 0 ? 'an' : 'a',
$type,
$this->toString()
$this->toString(),
);
}
}

View File

@@ -93,9 +93,8 @@ abstract class Constraint implements Countable, SelfDescribing
/**
* Throws an exception for the given compared value and test description.
*
* @param mixed $other evaluated value or object
* @param string $description Additional information about the test
* @param ComparisonFailure $comparisonFailure
* @param mixed $other evaluated value or object
* @param string $description Additional information about the test
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
@@ -106,7 +105,7 @@ abstract class Constraint implements Countable, SelfDescribing
{
$failureDescription = sprintf(
'Failed asserting that %s.',
$this->failureDescription($other)
$this->failureDescription($other),
);
$additionalFailureDescription = $this->additionalFailureDescription($other);
@@ -121,7 +120,7 @@ abstract class Constraint implements Countable, SelfDescribing
throw new ExpectationFailedException(
$failureDescription,
$comparisonFailure
$comparisonFailure,
);
}

View File

@@ -61,8 +61,6 @@ final class IsEqual extends Constraint
* failure.
*
* @throws ExpectationFailedException
*
* @return bool
*/
public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{
@@ -78,7 +76,7 @@ final class IsEqual extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
@@ -86,7 +84,7 @@ final class IsEqual extends Constraint
$other,
$this->delta,
$this->canonicalize,
$this->ignoreCase
$this->ignoreCase,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -95,7 +93,7 @@ final class IsEqual extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -118,21 +116,21 @@ final class IsEqual extends Constraint
return sprintf(
"is equal to '%s'",
$this->value
$this->value,
);
}
if ($this->delta != 0) {
$delta = sprintf(
' with delta <%F>',
$this->delta
$this->delta,
);
}
return sprintf(
'is equal to %s%s',
$this->exporter()->export($this->value),
$delta
$delta,
);
}
}

View File

@@ -58,7 +58,7 @@ final class IsEqualCanonicalizing extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
@@ -66,7 +66,7 @@ final class IsEqualCanonicalizing extends Constraint
$other,
0.0,
true,
false
false,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -75,7 +75,7 @@ final class IsEqualCanonicalizing extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -96,13 +96,13 @@ final class IsEqualCanonicalizing extends Constraint
return sprintf(
"is equal to '%s'",
$this->value
$this->value,
);
}
return sprintf(
'is equal to %s',
$this->exporter()->export($this->value)
$this->exporter()->export($this->value),
);
}
}

View File

@@ -58,7 +58,7 @@ final class IsEqualIgnoringCase extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
@@ -66,7 +66,7 @@ final class IsEqualIgnoringCase extends Constraint
$other,
0.0,
false,
true
true,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -75,7 +75,7 @@ final class IsEqualIgnoringCase extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -96,13 +96,13 @@ final class IsEqualIgnoringCase extends Constraint
return sprintf(
"is equal to '%s'",
$this->value
$this->value,
);
}
return sprintf(
'is equal to %s',
$this->exporter()->export($this->value)
$this->exporter()->export($this->value),
);
}
}

View File

@@ -62,13 +62,13 @@ final class IsEqualWithDelta extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
$this->value,
$other,
$this->delta
$this->delta,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -77,7 +77,7 @@ final class IsEqualWithDelta extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -94,7 +94,7 @@ final class IsEqualWithDelta extends Constraint
return sprintf(
'is equal to %s with delta <%F>',
$this->exporter()->export($this->value),
$this->delta
$this->delta,
);
}
}

View File

@@ -36,7 +36,7 @@ final class Exception extends Constraint
{
return sprintf(
'exception of type "%s"',
$this->className
$this->className,
);
}
@@ -73,13 +73,13 @@ final class Exception extends Constraint
'exception of type "%s" matches expected exception "%s"%s',
get_class($other),
$this->className,
$message
$message,
);
}
return sprintf(
'exception of type "%s" is thrown',
$this->className
$this->className,
);
}
}

View File

@@ -61,7 +61,7 @@ final class ExceptionCode extends Constraint
return sprintf(
'%s is equal to expected exception code %s',
$this->exporter()->export($other->getCode()),
$this->exporter()->export($this->expectedCode)
$this->exporter()->export($this->expectedCode),
);
}
}

View File

@@ -65,14 +65,14 @@ final class ExceptionMessage extends Constraint
if ($this->expectedMessage === '') {
return sprintf(
"exception message is empty but is '%s'",
$other->getMessage()
$other->getMessage(),
);
}
return sprintf(
"exception message '%s' contains '%s'",
$other->getMessage(),
$this->expectedMessage
$this->expectedMessage,
);
}
}

View File

@@ -48,7 +48,7 @@ final class ExceptionMessageRegularExpression extends Constraint
if ($match === false) {
throw new \PHPUnit\Framework\Exception(
"Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'"
"Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'",
);
}
@@ -68,7 +68,7 @@ final class ExceptionMessageRegularExpression extends Constraint
return sprintf(
"exception message '%s' matches '%s'",
$other->getMessage(),
$this->expectedMessageRegExp
$this->expectedMessageRegExp,
);
}
}

View File

@@ -48,7 +48,7 @@ final class DirectoryExists extends Constraint
{
return sprintf(
'directory "%s" exists',
$other
$other,
);
}
}

View File

@@ -48,7 +48,7 @@ final class FileExists extends Constraint
{
return sprintf(
'file "%s" exists',
$other
$other,
);
}
}

View File

@@ -48,7 +48,7 @@ final class IsReadable extends Constraint
{
return sprintf(
'"%s" is readable',
$other
$other,
);
}
}

View File

@@ -48,7 +48,7 @@ final class IsWritable extends Constraint
{
return sprintf(
'"%s" is writable',
$other
$other,
);
}
}

View File

@@ -62,7 +62,7 @@ final class IsIdentical extends Constraint
$this->value,
$other,
sprintf("'%s'", $this->value),
sprintf("'%s'", $other)
sprintf("'%s'", $other),
);
}
@@ -72,7 +72,7 @@ final class IsIdentical extends Constraint
$this->value,
$other,
$this->exporter()->export($this->value),
$this->exporter()->export($other)
$this->exporter()->export($other),
);
}

View File

@@ -37,7 +37,7 @@ final class JsonMatches extends Constraint
{
return sprintf(
'matches JSON string "%s"',
$this->value
$this->value,
);
}
@@ -69,9 +69,8 @@ final class JsonMatches extends Constraint
/**
* Throws an exception for the given compared value and test description.
*
* @param mixed $other evaluated value or object
* @param string $description Additional information about the test
* @param ComparisonFailure $comparisonFailure
* @param mixed $other evaluated value or object
* @param string $description Additional information about the test
*
* @throws \PHPUnit\Framework\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
@@ -100,7 +99,7 @@ final class JsonMatches extends Constraint
Json::prettify($recodedValue),
Json::prettify($recodedOther),
false,
'Failed asserting that two json values are equal.'
'Failed asserting that two json values are equal.',
);
}

View File

@@ -40,7 +40,7 @@ class ClassHasAttribute extends Constraint
{
return sprintf(
'has attribute "%s"',
$this->attributeName
$this->attributeName,
);
}
@@ -59,7 +59,7 @@ class ClassHasAttribute extends Constraint
throw new Exception(
$e->getMessage(),
$e->getCode(),
$e
$e,
);
}
// @codeCoverageIgnoreEnd
@@ -79,7 +79,7 @@ class ClassHasAttribute extends Constraint
'%sclass "%s" %s',
is_object($other) ? 'object of ' : '',
is_object($other) ? get_class($other) : $other,
$this->toString()
$this->toString(),
);
}

View File

@@ -28,7 +28,7 @@ final class ClassHasStaticAttribute extends ClassHasAttribute
{
return sprintf(
'has static attribute "%s"',
$this->attributeName()
$this->attributeName(),
);
}
@@ -51,7 +51,7 @@ final class ClassHasStaticAttribute extends ClassHasAttribute
throw new Exception(
$e->getMessage(),
$e->getCode(),
$e
$e,
);
}
// @codeCoverageIgnoreEnd

View File

@@ -65,7 +65,7 @@ final class ObjectEquals extends Constraint
if (!$object->hasMethod($this->method)) {
throw new ComparisonMethodDoesNotExistException(
get_class($other),
$this->method
$this->method,
);
}
@@ -75,7 +75,7 @@ final class ObjectEquals extends Constraint
if (!$method->hasReturnType()) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
@@ -84,28 +84,28 @@ final class ObjectEquals extends Constraint
if (!$returnType instanceof ReflectionNamedType) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
if ($returnType->allowsNull()) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
if ($returnType->getName() !== 'bool') {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
if ($method->getNumberOfParameters() !== 1 || $method->getNumberOfRequiredParameters() !== 1) {
throw new ComparisonMethodDoesNotDeclareExactlyOneParameterException(
get_class($other),
$this->method
$this->method,
);
}
@@ -114,7 +114,7 @@ final class ObjectEquals extends Constraint
if (!$parameter->hasType()) {
throw new ComparisonMethodDoesNotDeclareParameterTypeException(
get_class($other),
$this->method
$this->method,
);
}
@@ -123,7 +123,7 @@ final class ObjectEquals extends Constraint
if (!$type instanceof ReflectionNamedType) {
throw new ComparisonMethodDoesNotDeclareParameterTypeException(
get_class($other),
$this->method
$this->method,
);
}
@@ -137,7 +137,7 @@ final class ObjectEquals extends Constraint
throw new ComparisonMethodDoesNotAcceptParameterTypeException(
get_class($other),
$this->method,
get_class($this->expected)
get_class($this->expected),
);
}

View File

@@ -0,0 +1,84 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function get_class;
use function gettype;
use function is_object;
use function sprintf;
use ReflectionObject;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*/
final class ObjectHasProperty extends Constraint
{
/**
* @var string
*/
private $propertyName;
public function __construct(string $propertyName)
{
$this->propertyName = $propertyName;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return sprintf(
'has property "%s"',
$this->propertyName,
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if (!is_object($other)) {
return false;
}
return (new ReflectionObject($other))->hasProperty($this->propertyName);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
if (is_object($other)) {
return sprintf(
'object of class "%s" %s',
get_class($other),
$this->toString(),
);
}
return sprintf(
'"%s" (%s) %s',
$other,
gettype($other),
$this->toString(),
);
}
}

View File

@@ -63,15 +63,15 @@ final class LogicalNot extends UnaryOperator
preg_replace(
$positives,
$negatives,
$nonInput
$nonInput,
),
$string
$string,
);
} else {
$negatedString = preg_replace(
$positives,
$negatives,
$string
$string,
);
}

View File

@@ -57,7 +57,7 @@ final class LogicalXor extends BinaryOperator
{
return $matches xor $constraint->evaluate($other, '', true);
},
$initial->evaluate($other, '', true)
$initial->evaluate($other, '', true),
);
}
}

View File

@@ -65,13 +65,13 @@ final class IsJson extends Constraint
json_decode($other);
$error = (string) JsonMatchesErrorMessageProvider::determineJsonError(
(string) json_last_error()
(string) json_last_error(),
);
return sprintf(
'%s is valid JSON (%s)',
$this->exporter()->shortenedExport($other),
$error
$error,
);
}
}

View File

@@ -34,7 +34,7 @@ class RegularExpression extends Constraint
{
return sprintf(
'matches PCRE pattern "%s"',
$this->pattern
$this->pattern,
);
}

View File

@@ -48,7 +48,7 @@ final class StringContains extends Constraint
return sprintf(
'contains "%s"',
$string
$string,
);
}

View File

@@ -33,8 +33,8 @@ final class StringMatchesFormatDescription extends RegularExpression
{
parent::__construct(
$this->createPatternFromFormat(
$this->convertNewlines($string)
)
$this->convertNewlines($string),
),
);
$this->string = $string;
@@ -49,7 +49,7 @@ final class StringMatchesFormatDescription extends RegularExpression
protected function matches($other): bool
{
return parent::matches(
$this->convertNewlines($other)
$this->convertNewlines($other),
);
}
@@ -96,7 +96,7 @@ final class StringMatchesFormatDescription extends RegularExpression
'%x' => '[0-9a-fA-F]+',
'%f' => '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
'%c' => '.',
]
],
);
return '/^' . $string . '$/s';

View File

@@ -9,7 +9,6 @@
*/
namespace PHPUnit\Framework\Constraint;
use function strlen;
use function strpos;
use PHPUnit\Framework\InvalidArgumentException;
@@ -25,7 +24,7 @@ final class StringStartsWith extends Constraint
public function __construct(string $prefix)
{
if (strlen($prefix) === 0) {
if ($prefix === '') {
throw InvalidArgumentException::create(1, 'non-empty string');
}

View File

@@ -52,7 +52,7 @@ abstract class TraversableContains extends Constraint
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
$this->toString(),
);
}

View File

@@ -36,7 +36,7 @@ final class TraversableContainsOnly extends Constraint
$this->constraint = new IsType($type);
} else {
$this->constraint = new IsInstanceOf(
$type
$type,
);
}

View File

@@ -36,7 +36,7 @@ final class IsInstanceOf extends Constraint
return sprintf(
'is instance of %s "%s"',
$this->getType(),
$this->className
$this->className,
);
}
@@ -67,7 +67,7 @@ final class IsInstanceOf extends Constraint
'%s is an instance of %s "%s"',
$this->exporter()->shortenedExport($other),
$this->getType(),
$this->className
$this->className,
);
}

View File

@@ -130,8 +130,8 @@ final class IsType extends Constraint
sprintf(
'Type specified for PHPUnit\Framework\Constraint\IsType <%s> ' .
'is not a valid type.',
$type
)
$type,
),
);
}
@@ -145,7 +145,7 @@ final class IsType extends Constraint
{
return sprintf(
'is of type "%s"',
$this->type
$this->type,
);
}

View File

@@ -15,17 +15,17 @@ namespace PHPUnit\Framework;
final class ErrorTestCase extends TestCase
{
/**
* @var bool
* @var ?bool
*/
protected $backupGlobals = false;
/**
* @var bool
* @var ?bool
*/
protected $backupStaticAttributes = false;
/**
* @var bool
* @var ?bool
*/
protected $runTestInSeparateProcess = false;

View File

@@ -21,7 +21,7 @@ final class ActualValueIsNotAnObjectException extends Exception
parent::__construct(
'Actual value is not an object',
0,
null
null,
);
}

View File

@@ -24,10 +24,10 @@ final class ComparisonMethodDoesNotAcceptParameterTypeException extends Exceptio
'%s is not an accepted argument type for comparison method %s::%s().',
$type,
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

View File

@@ -23,10 +23,10 @@ final class ComparisonMethodDoesNotDeclareBoolReturnTypeException extends Except
sprintf(
'Comparison method %s::%s() does not declare bool return type.',
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

View File

@@ -23,10 +23,10 @@ final class ComparisonMethodDoesNotDeclareExactlyOneParameterException extends E
sprintf(
'Comparison method %s::%s() does not declare exactly one parameter.',
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

Some files were not shown because too many files have changed in this diff Show More