diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index a545c1b3..943c0957 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -17,6 +17,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" dependencies: - "lowest" - "highest" diff --git a/composer.json b/composer.json index 0baa4051..8633d49d 100644 --- a/composer.json +++ b/composer.json @@ -1,26 +1,28 @@ { "name": "magento/magento-semver", "description": "Magento Semantic Version Checker", - "version": "13.0.0-beta5", + "version": "13.0.0-beta9", "license": [ "OSL-3.0", "AFL-3.0" ], "bin": ["bin/svc"], "require": { - "php": "~8.1.0||~8.2.0||~8.3.0", + "php": "~8.1.0||~8.2.0||~8.3.0||~8.4.0", "ext-json": "*", "laminas/laminas-stdlib": "^3.18", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.19", "phpstan/phpdoc-parser": "^0.5.5", - "sabre/xml": "~2.2.3", - "symfony/console": "~6.4.0", + "sabre/xml": "~4.0.5", + "symfony/console": "~6.4.17", + "symfony/string": "~6.4.15", "tomzx/php-semver-checker": "^0.16.0", - "wikimedia/less.php": "^3.2" + "wikimedia/less.php": "^5.1" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^10.5", + "phpunit/phpunit": "~10.5.28", + "sebastian/cli-parser": "^2.0.1", "squizlabs/php_codesniffer": "~3.6.0" }, "autoload": { diff --git a/composer.lock b/composer.lock index 1bce5fca..908ebe88 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "33ac8c8057e26605bdd59f9d6162b506", + "content-hash": "28d690718f848ccaff782df0d832640a", "packages": [ { "name": "hassankhan/config", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/hassankhan/config.git", - "reference": "8e1c07f4fdc2b986b8a781f0dcba155af2a579b6" + "reference": "cf63da451c4d226df983017932b9cef1b6d49db5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hassankhan/config/zipball/8e1c07f4fdc2b986b8a781f0dcba155af2a579b6", - "reference": "8e1c07f4fdc2b986b8a781f0dcba155af2a579b6", + "url": "https://api.github.com/repos/hassankhan/config/zipball/cf63da451c4d226df983017932b9cef1b6d49db5", + "reference": "cf63da451c4d226df983017932b9cef1b6d49db5", "shasum": "" }, "require": { @@ -64,36 +64,36 @@ ], "support": { "issues": "https://github.com/hassankhan/config/issues", - "source": "https://github.com/hassankhan/config/tree/3.1.0" + "source": "https://github.com/hassankhan/config/tree/3.2.0" }, - "time": "2022-12-20T19:48:37+00:00" + "time": "2024-12-09T16:20:44+00:00" }, { "name": "laminas/laminas-stdlib", - "version": "3.19.0", + "version": "3.20.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "6a192dd0882b514e45506f533b833b623b78fff3" + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/6a192dd0882b514e45506f533b833b623b78fff3", - "reference": "6a192dd0882b514e45506f533b833b623b78fff3", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4", + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "zendframework/zend-stdlib": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.5", - "phpbench/phpbench": "^1.2.15", - "phpunit/phpunit": "^10.5.8", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.20.0" + "laminas/laminas-coding-standard": "^3.0", + "phpbench/phpbench": "^1.3.1", + "phpunit/phpunit": "^10.5.38", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" }, "type": "library", "autoload": { @@ -125,20 +125,20 @@ "type": "community_bridge" } ], - "time": "2024-01-19T12:39:49+00:00" + "time": "2024-10-29T13:46:07+00:00" }, { "name": "nikic/php-parser", - "version": "v4.19.1", + "version": "v4.19.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "shasum": "" }, "require": { @@ -147,7 +147,7 @@ }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -179,9 +179,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" }, - "time": "2024-03-17T08:10:35+00:00" + "time": "2024-09-29T15:01:53+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -287,27 +287,27 @@ }, { "name": "sabre/uri", - "version": "2.3.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sabre-io/uri.git", - "reference": "7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b" + "reference": "38eeab6ed9eec435a2188db489d4649c56272c51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/uri/zipball/7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b", - "reference": "7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b", + "url": "https://api.github.com/repos/sabre-io/uri/zipball/38eeab6ed9eec435a2188db489d4649c56272c51", + "reference": "38eeab6ed9eec435a2188db489d4649c56272c51", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.17", - "phpstan/extension-installer": "^1.3", - "phpstan/phpstan": "^1.10", - "phpstan/phpstan-phpunit": "^1.3", - "phpstan/phpstan-strict-rules": "^1.5", + "friendsofphp/php-cs-fixer": "^3.64", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^1.12", + "phpstan/phpstan-phpunit": "^1.4", + "phpstan/phpstan-strict-rules": "^1.6", "phpunit/phpunit": "^9.6" }, "type": "library", @@ -343,20 +343,20 @@ "issues": "https://github.com/sabre-io/uri/issues", "source": "https://github.com/fruux/sabre-uri" }, - "time": "2023-06-09T06:54:04+00:00" + "time": "2024-09-04T15:30:08+00:00" }, { "name": "sabre/xml", - "version": "2.2.6", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sabre-io/xml.git", - "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b" + "reference": "a89257fd188ce30e456b841b6915f27905dfdbe3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/xml/zipball/9cde7cdab1e50893cc83b037b40cd47bfde42a2b", - "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b", + "url": "https://api.github.com/repos/sabre-io/xml/zipball/a89257fd188ce30e456b841b6915f27905dfdbe3", + "reference": "a89257fd188ce30e456b841b6915f27905dfdbe3", "shasum": "" }, "require": { @@ -364,13 +364,13 @@ "ext-xmlreader": "*", "ext-xmlwriter": "*", "lib-libxml": ">=2.6.20", - "php": "^7.1 || ^8.0", - "sabre/uri": ">=1.0,<3.0.0" + "php": "^7.4 || ^8.0", + "sabre/uri": ">=2.0,<4.0.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.17.1", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0" + "friendsofphp/php-cs-fixer": "^3.64", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^9.6" }, "type": "library", "autoload": { @@ -412,20 +412,20 @@ "issues": "https://github.com/sabre-io/xml/issues", "source": "https://github.com/fruux/sabre-xml" }, - "time": "2023-06-28T12:56:05+00:00" + "time": "2024-09-06T08:00:55+00:00" }, { "name": "symfony/console", - "version": "v6.4.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2aaf83b4de5b9d43b93e4aec6f2f8b676f7c567e" + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2aaf83b4de5b9d43b93e4aec6f2f8b676f7c567e", - "reference": "2aaf83b4de5b9d43b93e4aec6f2f8b676f7c567e", + "url": "https://api.github.com/repos/symfony/console/zipball/a3011c7b7adb58d89f6c0d822abb641d7a5f9719", + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719", "shasum": "" }, "require": { @@ -490,7 +490,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.3" + "source": "https://github.com/symfony/console/tree/v6.4.21" }, "funding": [ { @@ -506,20 +506,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2025-04-07T15:42:41+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -527,12 +527,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -557,7 +557,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -573,24 +573,24 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -601,8 +601,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -636,7 +636,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -652,24 +652,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -677,8 +677,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -714,7 +714,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -730,24 +730,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -755,8 +755,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -795,7 +795,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -811,24 +811,25 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -839,8 +840,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -875,7 +876,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -891,37 +892,38 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.4.1", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -957,7 +959,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -973,20 +975,20 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/string", - "version": "v6.4.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "7a14736fb179876575464e4658fce0c304e8c15b" + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/7a14736fb179876575464e4658fce0c304e8c15b", - "reference": "7a14736fb179876575464e4658fce0c304e8c15b", + "url": "https://api.github.com/repos/symfony/string/zipball/73e2c6966a5aef1d4892873ed5322245295370c6", + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6", "shasum": "" }, "require": { @@ -1043,7 +1045,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.3" + "source": "https://github.com/symfony/string/tree/v6.4.21" }, "funding": [ { @@ -1059,20 +1061,20 @@ "type": "tidelift" } ], - "time": "2024-01-25T09:26:29+00:00" + "time": "2025-04-18T15:23:29+00:00" }, { "name": "symfony/yaml", - "version": "v6.4.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "d75715985f0f94f978e3a8fa42533e10db921b90" + "reference": "f01987f45676778b474468aa266fe2eda1f2bc7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/d75715985f0f94f978e3a8fa42533e10db921b90", - "reference": "d75715985f0f94f978e3a8fa42533e10db921b90", + "url": "https://api.github.com/repos/symfony/yaml/zipball/f01987f45676778b474468aa266fe2eda1f2bc7e", + "reference": "f01987f45676778b474468aa266fe2eda1f2bc7e", "shasum": "" }, "require": { @@ -1115,7 +1117,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.3" + "source": "https://github.com/symfony/yaml/tree/v6.4.21" }, "funding": [ { @@ -1131,7 +1133,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2025-04-04T09:48:44+00:00" }, { "name": "tomzx/finder", @@ -1252,28 +1254,28 @@ }, { "name": "wikimedia/less.php", - "version": "v3.2.1", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/wikimedia/less.php.git", - "reference": "0d5b30ba792bdbf8991a646fc9c30561b38a5559" + "reference": "fb0ed6296bb69cad225dd49b7e93765aab9ae88b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/less.php/zipball/0d5b30ba792bdbf8991a646fc9c30561b38a5559", - "reference": "0d5b30ba792bdbf8991a646fc9c30561b38a5559", + "url": "https://api.github.com/repos/wikimedia/less.php/zipball/fb0ed6296bb69cad225dd49b7e93765aab9ae88b", + "reference": "fb0ed6296bb69cad225dd49b7e93765aab9ae88b", "shasum": "" }, "require": { - "php": ">=7.2.9" + "php": ">=7.4.3" }, "require-dev": { - "mediawiki/mediawiki-codesniffer": "40.0.1", - "mediawiki/mediawiki-phan-config": "0.12.0", - "mediawiki/minus-x": "1.1.1", + "mediawiki/mediawiki-codesniffer": "46.0.0", + "mediawiki/mediawiki-phan-config": "0.15.1", + "mediawiki/minus-x": "1.1.3", "php-parallel-lint/php-console-highlighter": "1.0.0", - "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpunit/phpunit": "^8.5" + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpunit/phpunit": "9.6.21" }, "bin": [ "bin/lessc" @@ -1321,24 +1323,24 @@ ], "support": { "issues": "https://github.com/wikimedia/less.php/issues", - "source": "https://github.com/wikimedia/less.php/tree/v3.2.1" + "source": "https://github.com/wikimedia/less.php/tree/v5.3.1" }, - "time": "2023-02-03T06:43:41+00:00" + "time": "2025-04-16T22:21:45+00:00" } ], "packages-dev": [ { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", "shasum": "" }, "require": { @@ -1346,11 +1348,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -1376,7 +1379,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" }, "funding": [ { @@ -1384,7 +1387,7 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2025-04-29T12:36:36+00:00" }, { "name": "phar-io/manifest", @@ -1506,32 +1509,32 @@ }, { "name": "phpunit/php-code-coverage", - "version": "10.1.14", + "version": "10.1.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=8.1", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-text-template": "^3.0", - "sebastian/code-unit-reverse-lookup": "^3.0", - "sebastian/complexity": "^3.0", - "sebastian/environment": "^6.0", - "sebastian/lines-of-code": "^2.0", - "sebastian/version": "^4.0", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { "phpunit/phpunit": "^10.1" @@ -1543,7 +1546,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.1-dev" + "dev-main": "10.1.x-dev" } }, "autoload": { @@ -1572,7 +1575,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" }, "funding": [ { @@ -1580,7 +1583,7 @@ "type": "github" } ], - "time": "2024-03-12T15:33:41+00:00" + "time": "2024-08-22T04:31:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1827,16 +1830,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.19", + "version": "10.5.46", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c726f0de022368f6ed103e452a765d3304a996a4" + "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c726f0de022368f6ed103e452a765d3304a996a4", - "reference": "c726f0de022368f6ed103e452a765d3304a996a4", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8080be387a5be380dda48c6f41cee4a13aadab3d", + "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d", "shasum": "" }, "require": { @@ -1846,26 +1849,26 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.5", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-invoker": "^4.0", - "phpunit/php-text-template": "^3.0", - "phpunit/php-timer": "^6.0", - "sebastian/cli-parser": "^2.0", - "sebastian/code-unit": "^2.0", - "sebastian/comparator": "^5.0", - "sebastian/diff": "^5.0", - "sebastian/environment": "^6.0", - "sebastian/exporter": "^5.1", - "sebastian/global-state": "^6.0.1", - "sebastian/object-enumerator": "^5.0", - "sebastian/recursion-context": "^5.0", - "sebastian/type": "^4.0", - "sebastian/version": "^4.0" + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.3", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -1908,7 +1911,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.19" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.46" }, "funding": [ { @@ -1919,12 +1922,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2024-04-17T14:06:18+00:00" + "time": "2025-05-02T06:46:24+00:00" }, { "name": "sebastian/cli-parser", @@ -2096,16 +2107,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.1", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372" + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", "shasum": "" }, "require": { @@ -2116,7 +2127,7 @@ "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.3" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -2161,7 +2172,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" }, "funding": [ { @@ -2169,7 +2180,7 @@ "type": "github" } ], - "time": "2023-08-14T13:18:12+00:00" + "time": "2024-10-18T14:56:07+00:00" }, { "name": "sebastian/complexity", @@ -2965,15 +2976,15 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~8.1.0||~8.2.0||~8.3.0", + "php": "~8.1.0||~8.2.0||~8.3.0||~8.4.0", "ext-json": "*" }, "platform-dev": { "ext-dom": "*" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.6.0" } diff --git a/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php b/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php index 82d4ed6c..32dadfe9 100644 --- a/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php +++ b/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php @@ -59,10 +59,10 @@ public static function changesDataProvider() $pathToFixtures . '/new-method/source-code-before', $pathToFixtures . '/new-method/source-code-after', [ - 'Class (PATCH)', + 'Class (MINOR)', 'Test\Vcs\TestClass::testMethod | [public] Method has been added. | V015' ], - 'Patch change is detected.' + 'Minor change is detected.' ], 'api-class-removed-class' => [ $pathToFixtures . '/removed-class/source-code-before', diff --git a/dev/tests/Unit/Console/Command/CompareSourceCommandLessTest.php b/dev/tests/Unit/Console/Command/CompareSourceCommandLessTest.php index 1790a97e..6c384ca3 100644 --- a/dev/tests/Unit/Console/Command/CompareSourceCommandLessTest.php +++ b/dev/tests/Unit/Console/Command/CompareSourceCommandLessTest.php @@ -98,7 +98,7 @@ public static function changesDataProvider() $pathToFixtures . '/removed-import/source-code-after', [ '/Less \(MAJOR\)/', - '/view\/frontend\/web\/css\/source\/test.less:0\s*\|\s*Import with value: \'testimport\'\s*\|\s*A less import-node was removed\s*\|\s*M402/' + '/view\/frontend\/web\/css\/source\/test.less:0\s*\|\s*Less_Tree_Import\s*\|\s*A less import-node was removed\s*\|\s*M402/' ], 'Major change is detected.', ], @@ -107,8 +107,8 @@ public static function changesDataProvider() $pathToFixtures . '/removed-imports/source-code-after', [ '/Less \(MAJOR\)/', - '/view\/frontend\/web\/css\/source\/test.less:0\s*\|\s*Import with value: \'testimport\'\s*\|\s*A less import-node was removed\s*\|\s*M402/', - '/view\/frontend\/web\/css\/source\/test.less:0\s*\|\s*Import with value: \'testimport2\'\s*\|\s*A less import-node was removed\s*\|\s*M402/' + '/view\/frontend\/web\/css\/source\/test.less:0\s*\|\s*Less_Tree_Import\s*\|\s*A less import-node was removed\s*\|\s*M402/', + '/view\/frontend\/web\/css\/source\/test.less:0\s*\|\s*Less_Tree_Import\s*\|\s*A less import-node was removed\s*\|\s*M402/' ], 'Major change is detected.', ], diff --git a/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter-for-extendable/source-code-after/AbstractExtensibleModel.php b/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter-for-extendable/source-code-after/AbstractExtensibleModel.php index f31f3ba9..920786e7 100644 --- a/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter-for-extendable/source-code-after/AbstractExtensibleModel.php +++ b/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter-for-extendable/source-code-after/AbstractExtensibleModel.php @@ -11,7 +11,7 @@ */ class AbstractExtensibleModel { - public function __construct(\Test\Vcs\TestInterface $a, \Test\Vcs\TestInterface $b = null) + public function __construct(\Test\Vcs\TestInterface $a, ?\Test\Vcs\TestInterface $b = null) { } } diff --git a/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter/source-code-after/TestClass.php b/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter/source-code-after/TestClass.php index f0d494eb..fbdf0168 100644 --- a/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter/source-code-after/TestClass.php +++ b/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/api-class/new-optional-constructor-parameter/source-code-after/TestClass.php @@ -11,7 +11,7 @@ */ class TestClass { - public function __construct(\Test\Vcs\TestInterface $a, \Test\Vcs\TestInterface $b = null) + public function __construct(\Test\Vcs\TestInterface $a, ?\Test\Vcs\TestInterface $b = null) { } } diff --git a/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/non-api-class/new-optional-constructor-parameter/source-code-after/TestClass.php b/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/non-api-class/new-optional-constructor-parameter/source-code-after/TestClass.php index 25696461..50537bd9 100644 --- a/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/non-api-class/new-optional-constructor-parameter/source-code-after/TestClass.php +++ b/dev/tests/Unit/Console/Command/CompareSourceCommandTest/_files/non-api-class/new-optional-constructor-parameter/source-code-after/TestClass.php @@ -8,7 +8,7 @@ class TestClass { - public function __construct(\Test\Vcs\TestInterface $a, \Test\Vcs\TestInterface $b = null) + public function __construct(\Test\Vcs\TestInterface $a, ?\Test\Vcs\TestInterface $b = null) { } } diff --git a/dev/tests/Unit/bootstrap.php b/dev/tests/Unit/bootstrap.php index 0481b696..e5c95dd5 100644 --- a/dev/tests/Unit/bootstrap.php +++ b/dev/tests/Unit/bootstrap.php @@ -37,7 +37,6 @@ function ($errNo, $errStr, $errFile, $errLine) { E_USER_ERROR => 'User Error', E_USER_WARNING => 'User Warning', E_USER_NOTICE => 'User Notice', - E_STRICT => 'Strict', E_RECOVERABLE_ERROR => 'Recoverable Error', E_DEPRECATED => 'Deprecated', E_USER_DEPRECATED => 'User Deprecated', diff --git a/src/Analyzer/AbstractCodeAnalyzer.php b/src/Analyzer/AbstractCodeAnalyzer.php index 1bf4d16a..8bcc6805 100644 --- a/src/Analyzer/AbstractCodeAnalyzer.php +++ b/src/Analyzer/AbstractCodeAnalyzer.php @@ -51,7 +51,7 @@ public function __construct( $context = null, $fileBefore = null, $fileAfter = null, - DependencyGraph $dependencyGraph = null + ?DependencyGraph $dependencyGraph = null ) { $this->context = $context; $this->fileBefore = $fileBefore; diff --git a/src/Analyzer/ClassLikeApiAnnotationAnalyzer.php b/src/Analyzer/ClassLikeApiAnnotationAnalyzer.php index 2b28661e..105b41d5 100644 --- a/src/Analyzer/ClassLikeApiAnnotationAnalyzer.php +++ b/src/Analyzer/ClassLikeApiAnnotationAnalyzer.php @@ -35,7 +35,7 @@ public function __construct( $context = null, $fileBefore = null, $fileAfter = null, - DependencyGraph $dependencyGraph = null + ?DependencyGraph $dependencyGraph = null ) { parent::__construct($context, $fileBefore, $fileAfter, $dependencyGraph); $this->nodeHelper = new Node(); diff --git a/src/Analyzer/ClassMethodAnalyzer.php b/src/Analyzer/ClassMethodAnalyzer.php index c399e433..bca5078d 100644 --- a/src/Analyzer/ClassMethodAnalyzer.php +++ b/src/Analyzer/ClassMethodAnalyzer.php @@ -41,6 +41,7 @@ use PHPSemVerChecker\Operation\ClassMethodParameterTypingRemoved; use PHPSemVerChecker\Operation\ClassMethodRemoved; use PHPSemVerChecker\Report\Report; +use Magento\SemanticVersionChecker\Operation\ClassMethodParameterTypingChangedNullable; /** * Class method analyzer. @@ -258,12 +259,24 @@ protected function reportChanged($report, $contextBefore, $contextAfter, $method $report->add($this->context, $data); $signatureChanged = true; } elseif ($signatureChanges['parameter_typing_changed']) { - $data = new ClassMethodParameterTypingChanged( - $this->context, - $this->fileAfter, - $contextAfter, - $methodAfter - ); + if ( + $signatureChanges['parameter_nullable_type_added'] + || $signatureChanges['parameter_nullable_type_removed'] + ) { + $data = new ClassMethodParameterTypingChangedNullable( + $this->context, + $this->fileAfter, + $contextAfter, + $methodAfter + ); + } else { + $data = new ClassMethodParameterTypingChanged( + $this->context, + $this->fileAfter, + $contextAfter, + $methodAfter + ); + } $report->add($this->context, $data); $signatureChanged = true; } diff --git a/src/Analyzer/Factory/AnalyzerFactory.php b/src/Analyzer/Factory/AnalyzerFactory.php index b7aae2d2..4ab0b5b8 100644 --- a/src/Analyzer/Factory/AnalyzerFactory.php +++ b/src/Analyzer/Factory/AnalyzerFactory.php @@ -25,7 +25,7 @@ class AnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $analyzers = [ new ApiClassAnalyzer(null, null, null, $dependencyGraph), diff --git a/src/Analyzer/Factory/AnalyzerFactoryInterface.php b/src/Analyzer/Factory/AnalyzerFactoryInterface.php index 63dc27ea..fed7828e 100644 --- a/src/Analyzer/Factory/AnalyzerFactoryInterface.php +++ b/src/Analyzer/Factory/AnalyzerFactoryInterface.php @@ -21,5 +21,5 @@ interface AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface; + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface; } diff --git a/src/Analyzer/Factory/DbSchemaAnalyzerFactory.php b/src/Analyzer/Factory/DbSchemaAnalyzerFactory.php index 32eb0dbc..7910b8e6 100644 --- a/src/Analyzer/Factory/DbSchemaAnalyzerFactory.php +++ b/src/Analyzer/Factory/DbSchemaAnalyzerFactory.php @@ -30,7 +30,7 @@ class DbSchemaAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new Report(); $analyzers = [ diff --git a/src/Analyzer/Factory/DiAnalyzerFactory.php b/src/Analyzer/Factory/DiAnalyzerFactory.php index 0260bbe3..ea9a9bf5 100644 --- a/src/Analyzer/Factory/DiAnalyzerFactory.php +++ b/src/Analyzer/Factory/DiAnalyzerFactory.php @@ -24,7 +24,7 @@ class DiAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new DbSchemaReport(); $analyzers = [ diff --git a/src/Analyzer/Factory/EtSchemaAnalyzerFactory.php b/src/Analyzer/Factory/EtSchemaAnalyzerFactory.php index a00f3aa6..374b5d12 100644 --- a/src/Analyzer/Factory/EtSchemaAnalyzerFactory.php +++ b/src/Analyzer/Factory/EtSchemaAnalyzerFactory.php @@ -22,7 +22,7 @@ */ class EtSchemaAnalyzerFactory implements AnalyzerFactoryInterface { - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new DbSchemaReport(); $analyzers = [ diff --git a/src/Analyzer/Factory/LayoutAnalyzerFactory.php b/src/Analyzer/Factory/LayoutAnalyzerFactory.php index 37078910..6ccf54df 100644 --- a/src/Analyzer/Factory/LayoutAnalyzerFactory.php +++ b/src/Analyzer/Factory/LayoutAnalyzerFactory.php @@ -24,7 +24,7 @@ class LayoutAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new DbSchemaReport(); $analyzers = [ diff --git a/src/Analyzer/Factory/LessAnalyzerFactory.php b/src/Analyzer/Factory/LessAnalyzerFactory.php index e83600a7..3c57d713 100644 --- a/src/Analyzer/Factory/LessAnalyzerFactory.php +++ b/src/Analyzer/Factory/LessAnalyzerFactory.php @@ -24,7 +24,7 @@ class LessAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new DbSchemaReport(); $analyzers = [ diff --git a/src/Analyzer/Factory/MftfAnalyzerFactory.php b/src/Analyzer/Factory/MftfAnalyzerFactory.php index e1fe7958..92b5f86c 100644 --- a/src/Analyzer/Factory/MftfAnalyzerFactory.php +++ b/src/Analyzer/Factory/MftfAnalyzerFactory.php @@ -30,7 +30,7 @@ class MftfAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new MftfReport(); $analyzers = [ diff --git a/src/Analyzer/Factory/NonApiAnalyzerFactory.php b/src/Analyzer/Factory/NonApiAnalyzerFactory.php index c20dea44..32d26109 100644 --- a/src/Analyzer/Factory/NonApiAnalyzerFactory.php +++ b/src/Analyzer/Factory/NonApiAnalyzerFactory.php @@ -25,7 +25,7 @@ class NonApiAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $analyzers = [ new ClassAnalyzer(null, null, null, $dependencyGraph), diff --git a/src/Analyzer/Factory/SystemXmlAnalyzerFactory.php b/src/Analyzer/Factory/SystemXmlAnalyzerFactory.php index b2760610..65d7a205 100644 --- a/src/Analyzer/Factory/SystemXmlAnalyzerFactory.php +++ b/src/Analyzer/Factory/SystemXmlAnalyzerFactory.php @@ -24,7 +24,7 @@ class SystemXmlAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new DbSchemaReport(); $analyzers = [ diff --git a/src/Analyzer/Factory/XsdAnalyzerFactory.php b/src/Analyzer/Factory/XsdAnalyzerFactory.php index f30b41a2..11bf6108 100644 --- a/src/Analyzer/Factory/XsdAnalyzerFactory.php +++ b/src/Analyzer/Factory/XsdAnalyzerFactory.php @@ -24,7 +24,7 @@ class XsdAnalyzerFactory implements AnalyzerFactoryInterface * @param DependencyGraph|null $dependencyGraph * @return AnalyzerInterface */ - public function create(DependencyGraph $dependencyGraph = null): AnalyzerInterface + public function create(?DependencyGraph $dependencyGraph = null): AnalyzerInterface { $report = new DbSchemaReport(); $analyzers = [ diff --git a/src/Analyzer/Less/Analyzer.php b/src/Analyzer/Less/Analyzer.php index 1ef3fe02..285a04b2 100644 --- a/src/Analyzer/Less/Analyzer.php +++ b/src/Analyzer/Less/Analyzer.php @@ -20,7 +20,7 @@ use PHPSemVerChecker\Report\Report; use Less_Tree; use Less_Tree_Comment; -use Less_Tree_Rule; +use Less_Tree_Declaration; use Less_Tree_Mixin_Definition; use Less_Tree_Import; @@ -152,7 +152,7 @@ private function reportRemovedNodes(string $file, array $nodes) { foreach ($nodes as $nodeName => $node) { switch (true) { - case $node instanceof Less_Tree_Rule: + case $node instanceof Less_Tree_Declaration: $this->report->add(self::CONTEXT, new VariableRemoved($file, $nodeName)); break; case $node instanceof Less_Tree_Mixin_Definition: diff --git a/src/Analyzer/SystemXml/Analyzer.php b/src/Analyzer/SystemXml/Analyzer.php index 5fe050a3..d1b2206c 100644 --- a/src/Analyzer/SystemXml/Analyzer.php +++ b/src/Analyzer/SystemXml/Analyzer.php @@ -25,6 +25,8 @@ use Magento\SemanticVersionChecker\Registry\XmlRegistry; use PHPSemVerChecker\Registry\Registry; use PHPSemVerChecker\Report\Report; +use Magento\SemanticVersionChecker\Operation\SystemXml\DuplicateFieldAdded; +use RecursiveDirectoryIterator; /** * Analyzes system.xml files: @@ -92,14 +94,152 @@ public function analyze($registryBefore, $registryAfter) $beforeFile = $registryBefore->mapping[XmlRegistry::NODES_KEY][$moduleName]; $this->reportRemovedNodes($beforeFile, $removedNodes); } + if ($addedNodes) { $afterFile = $registryAfter->mapping[XmlRegistry::NODES_KEY][$moduleName]; - $this->reportAddedNodes($afterFile, $addedNodes); + if (strpos($afterFile, '_files') !== false) { + $this->reportAddedNodes($afterFile, $addedNodes); + } else { + $baseDir = $this->getBaseDir($afterFile); + foreach ($addedNodes as $nodeId => $node) { + $newNodeData = $this->getNodeData($node); + $nodePath = $newNodeData['path']; + + // Extract section, group, and fieldId with error handling + $extractedData = $this->extractSectionGroupField($nodePath); + if ($extractedData === null) { + // Skip the node if its path is invalid + continue; + } + + // Extract section, group, and fieldId + list($sectionId, $groupId, $fieldId) = $extractedData; + + // Call function to check if this field is duplicated in other system.xml files + $isDuplicated = $this->isDuplicatedFieldInXml( + $baseDir, + $sectionId, + $groupId, + $fieldId, + $afterFile + ); + + foreach ($isDuplicated as $isDuplicatedItem) { + if ($isDuplicatedItem['status'] === 'duplicate') { + $this->reportDuplicateNodes($afterFile, [$nodeId => $node]); + } else { + $this->reportAddedNodes($afterFile, [$nodeId => $node]); + } + } + } + } } } return $this->report; } + /** + * Get Magento Base directory from the path + * + * @param string $filePath + * @return string|null + */ + private function getBaseDir(string $filePath): ?string + { + $currentDir = dirname($filePath); + while ($currentDir !== '/' && $currentDir !== false) { + // Check if current directory contains files unique to Magento root + if (file_exists($currentDir . '/SECURITY.md')) { + return $currentDir; // Found the Magento base directory + } + $currentDir = dirname($currentDir); + } + return null; + } + + /** + * Search for system.xml files in both app/code and vendor directories, excluding the provided file. + * + * @param string $magentoBaseDir The base directory of Magento. + * @param string|null $excludeFile The file to exclude from the search. + * @return array An array of paths to system.xml files, excluding the specified file. + */ + private function getSystemXmlFiles(string $magentoBaseDir, ?string $excludeFile = null): array + { + $systemXmlFiles = []; + $directoryToSearch = [ + $magentoBaseDir . '/app/code' + ]; + + // Check if 'vendor' directory exists, and only add it if it does + if (is_dir($magentoBaseDir . '/vendor')) { + $directoriesToSearch[] = $magentoBaseDir . '/vendor'; + } + foreach ($directoryToSearch as $directory) { + $iterator = new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); + foreach ($iterator as $file) { + if ($file->getfileName() === 'system.xml') { + $filePath = $file->getRealPath(); + if ($filePath !== $excludeFile) { + $systemXmlFiles[] = $file->getRealPath(); + } + } + } + } + return $systemXmlFiles; + } + + /** + * Method to extract section, group and field from the Node + * + * @param string $nodePath + * @return array|null + */ + private function extractSectionGroupField(string $nodePath): ?array + { + $parts = explode('/', $nodePath); + + if (count($parts) < 3) { + // Invalid path if there are fewer than 3 parts + return null; + } + + $sectionId = $parts[0]; + $groupId = $parts[1]; + $fieldId = $parts[2]; + + return [$sectionId, $groupId, $fieldId]; + } + + /** + * Method to get Node Data using reflection class + * + * @param object|string $node + * @return array + * @throws \ReflectionException + */ + private function getNodeData(object|string $node): array + { + $data = []; + + // Use reflection to get accessible properties + $reflection = new \ReflectionClass($node); + foreach ($reflection->getMethods() as $method) { + // Skip 'getId' and 'getParent' methods for comparison + if ($method->getName() === 'getId' || $method->getName() === 'getParent') { + continue; + } + + // Dynamically call the getter methods + if (strpos($method->getName(), 'get') === 0) { + $propertyName = lcfirst(str_replace('get', '', $method->getName())); + $data[$propertyName] = $method->invoke($node); + } + } + + return $data; + } + /** * Extracts the node from $registry as an associative array. * @@ -164,13 +304,32 @@ private function reportAddedNodes(string $file, array $nodes) } } + /** + * Creates reports for $nodes considering that they have been duplicated. + * + * @param string $file + * @param NodeInterface[] $nodes + * @return void + */ + private function reportDuplicateNodes(string $file, array $nodes): void + { + foreach ($nodes as $node) { + switch (true) { + case $node instanceof Field: + $this->report->add('system', new DuplicateFieldAdded($file, $node->getPath())); + break; + } + } + } + /** * Creates reports for $modules considering that system.xml has been removed from them. * * @param array $modules * @param XmlRegistry $registryBefore + * @return void */ - private function reportRemovedFiles(array $modules, XmlRegistry $registryBefore) + private function reportRemovedFiles(array $modules, XmlRegistry $registryBefore): void { foreach ($modules as $module) { $beforeFile = $registryBefore->mapping[XmlRegistry::NODES_KEY][$module]; @@ -183,8 +342,9 @@ private function reportRemovedFiles(array $modules, XmlRegistry $registryBefore) * * @param string $file * @param NodeInterface[] $nodes + * @return void */ - private function reportRemovedNodes(string $file, array $nodes) + private function reportRemovedNodes(string $file, array $nodes): void { foreach ($nodes as $node) { switch (true) { @@ -202,4 +362,56 @@ private function reportRemovedNodes(string $file, array $nodes) } } } + + /** + * @param string|null $baseDir + * @param string $sectionId + * @param string $groupId + * @param string|null $fieldId + * @param string $afterFile + * @return array + */ + private function isDuplicatedFieldInXml( + ?string $baseDir, + string $sectionId, + string $groupId, + ?string $fieldId, + string $afterFile + ): array { + $hasDuplicate = false; + + $result = [ + 'status' => 'minor', + 'field' => $fieldId + ]; + + if ($baseDir) { + $systemXmlFiles = $this->getSystemXmlFiles($baseDir, $afterFile); + + foreach ($systemXmlFiles as $systemXmlFile) { + $xmlContent = file_get_contents($systemXmlFile); + try { + $xml = new \SimpleXMLElement($xmlContent); + } catch (\Exception $e) { + continue; // Skip this file if there's a parsing error + } + // Find nodes with the given field ID + // XPath to search for within a specific section and group + $fields = $xml->xpath("//section[@id='$sectionId']/group[@id='$groupId']/field[@id='$fieldId']"); + if (!empty($fields)) { + $hasDuplicate = true; // Set the duplicate flag to true if a match is found + break; // Since we found a duplicate, we don't need to check further for this field + } + } + if ($hasDuplicate) { + return [ + [ + 'status' => 'duplicate', + 'field' => $fieldId + ] + ]; + } + } + return [$result]; + } } diff --git a/src/Comparator/Signature.php b/src/Comparator/Signature.php index 2ce20c1a..bbcf4e33 100644 --- a/src/Comparator/Signature.php +++ b/src/Comparator/Signature.php @@ -10,6 +10,7 @@ namespace Magento\SemanticVersionChecker\Comparator; use PHPSemVerChecker\Comparator\Node; +use PhpParser\Node\NullableType; class Signature extends \PHPSemVerChecker\Comparator\Signature { @@ -47,6 +48,7 @@ public static function isOptionalParams(array $params) /** * Checks type hinting to determine if each parameter is non-Scalar. + * * It assumes proper PHP code style is followed, meaning only non-Scalar parameters have type hinting. * * @param array $params Array of PhpParser\Node\Param objects @@ -130,18 +132,34 @@ public static function analyze(array $parametersA, array $parametersB): array $changes = array_merge($changes, [ 'parameter_typing_added' => false, 'parameter_typing_removed' => false, - 'parameter_typing_changed' => false + 'parameter_typing_changed' => false, + 'parameter_nullable_type_added' => false, + 'parameter_nullable_type_removed' => false ]); $lengthA = count($parametersA); $lengthB = count($parametersB); $iterations = min($lengthA, $lengthB); for ($i = 0; $i < $iterations; ++$i) { + $typeBefore = $parametersA[$i]->type; + $typeAfter = $parametersB[$i]->type; // Re-implement type checking to handle type changes as a single operation instead of both add and remove if (Type::get($parametersA[$i]->type) !== Type::get($parametersB[$i]->type)) { // This section changed from parent::analyze() to handle typing changes if ($parametersA[$i]->type !== null && $parametersB[$i]->type !== null) { $changes['parameter_typing_changed'] = true; + // Custom: detect nullable added + if ( + $typeBefore instanceof NullableType + && !$typeAfter instanceof NullableType + ) { + $changes['parameter_nullable_type_added'] = true; + } elseif ( + !$typeBefore instanceof NullableType + && $typeAfter instanceof NullableType + ) { + $changes['parameter_nullable_type_removed'] = true; + } } elseif ($parametersA[$i]->type !== null) { $changes['parameter_typing_removed'] = true; } elseif ($parametersB[$i]->type !== null) { @@ -149,7 +167,6 @@ public static function analyze(array $parametersA, array $parametersB): array } } } - return $changes; } } diff --git a/src/Operation/ClassMethodParameterTypingChangedNullable.php b/src/Operation/ClassMethodParameterTypingChangedNullable.php new file mode 100644 index 00000000..52868e26 --- /dev/null +++ b/src/Operation/ClassMethodParameterTypingChangedNullable.php @@ -0,0 +1,53 @@ + ['M113', 'M114', 'M115'], + 'interface' => ['M116'], + 'trait' => ['M117', 'M118', 'M119'] + ]; + + /** + * @var array + */ + private $mapping = [ + 'M113' => Level::PATCH, + 'M114' => Level::MAJOR, + 'M115' => Level::PATCH, + 'M116' => Level::MAJOR, + 'M117' => Level::MAJOR, + 'M118' => Level::MAJOR, + 'M119' => Level::MAJOR + ]; + + /** + * @var string + */ + protected $reason = 'Method parameter typing changed.'; + + /** + * Returns level of error. + * + * @return mixed + */ + public function getLevel(): int + { + return $this->mapping[$this->getCode()]; + } +} diff --git a/src/Operation/SystemXml/DuplicateFieldAdded.php b/src/Operation/SystemXml/DuplicateFieldAdded.php new file mode 100644 index 00000000..8424574e --- /dev/null +++ b/src/Operation/SystemXml/DuplicateFieldAdded.php @@ -0,0 +1,34 @@ +field node is added. + */ +class DuplicateFieldAdded extends AbstractOperation +{ + /** + * @var string + */ + protected $code = 'M302'; + + /** + * @var int + */ + protected $level = Level::PATCH; + + /** + * @var string + */ + protected $reason = 'A field-node was duplicated'; +} diff --git a/src/ReportBuilder.php b/src/ReportBuilder.php index d9e391af..e39d8682 100644 --- a/src/ReportBuilder.php +++ b/src/ReportBuilder.php @@ -126,7 +126,7 @@ protected function makeVersionReport() // Customize severity level of some @api changes LevelMapping::setOverrides( [ - 'V015' => Level::PATCH, // Add public method + 'V015' => Level::MINOR, // Add public method 'V016' => Level::PATCH, // Add protected method 'V019' => Level::MINOR, // Add public property 'V020' => Level::MINOR, // Add protected property diff --git a/src/Reporter/BreakingChangeTableReporter.php b/src/Reporter/BreakingChangeTableReporter.php index 3ae55e7f..8d7286f3 100644 --- a/src/Reporter/BreakingChangeTableReporter.php +++ b/src/Reporter/BreakingChangeTableReporter.php @@ -10,12 +10,14 @@ use PHPSemVerChecker\Report\Report; use PHPSemVerChecker\SemanticVersioning\Level; use Symfony\Component\Console\Output\OutputInterface; +use PHPSemVerChecker\Operation\Operation; class BreakingChangeTableReporter extends TableReporter { private $breakChangeLevels = [ Level::MAJOR, Level::MINOR, + Level::PATCH, ]; /** @@ -96,24 +98,71 @@ private function outputChangeReport(OutputInterface $output, Report $report, $co protected function outputTable(OutputInterface $output, Report $report, $context) { $table = new HtmlTableRenderer($output); - $table->setHeaders(['What changed', 'How it changed']); + $table->setHeaders(['Change Level', 'What Changed', 'How It Changed']); $rows = []; foreach (Level::asList('desc') as $level) { if (!in_array($level, $this->breakChangeLevels)) { continue; } $reportForLevel = $report[$context][$level]; - /** @var \PHPSemVerChecker\Operation\Operation $operation */ + /** @var Operation $operation */ foreach ($reportForLevel as $operation) { + // Skip private method/property changes as they shouldn't be in breaking change reports + if ($this->isPrivateMemberChange($operation)) { + continue; + } + + $levelLabel = $this->getLevelLabel($level); $target = $operation->getTarget(); $reason = $operation->getReason(); - $rows[] = [$target, $reason]; + $rows[] = [$levelLabel, $target, $reason]; } } $table->setRows($rows); $table->render(); } + /** + * Get a human-readable label for the change level + * + * @param int $level + * @return string + */ + private function getLevelLabel(int $level): string + { + switch ($level) { + case Level::MAJOR: + return 'MAJOR (Breaking)'; + case Level::MINOR: + return 'MINOR (Non-breaking)'; + case Level::PATCH: + return 'PATCH'; + default: + return 'UNKNOWN'; + } + } + + /** + * Check if the operation represents a private method or property change + * + * Private changes are filtered out as they don't affect the public API contract. + * + * @param Operation $operation + * @return bool + */ + private function isPrivateMemberChange(Operation $operation): bool + { + $target = $operation->getTarget(); + $reason = $operation->getReason(); + + // Simple string check for 'private' keyword (covers all cases) + if (stripos($target, 'private') !== false || stripos($reason, 'private') !== false) { + return true; + } + + return false; + } + /** * Generate the HTML header line for a report section * diff --git a/src/Scanner/ScannerRegistryFactory.php b/src/Scanner/ScannerRegistryFactory.php index f05e8af3..741e4040 100644 --- a/src/Scanner/ScannerRegistryFactory.php +++ b/src/Scanner/ScannerRegistryFactory.php @@ -55,8 +55,8 @@ private function buildFullScanner() * @return Scanner */ private function buildApiScanner( - DependencyGraph $dependencyGraph = null, - DependencyGraph $dependencyGraphCompare = null + ?DependencyGraph $dependencyGraph = null, + ?DependencyGraph $dependencyGraphCompare = null ) { $registry = new Registry(); $parser = new Parser(new Emulative()); @@ -80,7 +80,7 @@ private function buildApiScanner( * @param boolean $mftf * @return array */ - public function create(DependencyGraph $dependencyGraph = null, DependencyGraph $dependencyGraphCompare = null) + public function create(?DependencyGraph $dependencyGraph = null, ?DependencyGraph $dependencyGraphCompare = null) { $moduleNameResolver = new ModuleNamespaceResolver(); diff --git a/src/Visitor/AbstractApiVisitor.php b/src/Visitor/AbstractApiVisitor.php index 41945863..8c28b865 100644 --- a/src/Visitor/AbstractApiVisitor.php +++ b/src/Visitor/AbstractApiVisitor.php @@ -40,8 +40,8 @@ abstract class AbstractApiVisitor extends NodeVisitorAbstract public function __construct( Registry $registry, NodeHelper $nodeHelper, - DependencyGraph $dependencyGraph = null, - DependencyGraph $dependencyGraphCompare = null + ?DependencyGraph $dependencyGraph = null, + ?DependencyGraph $dependencyGraphCompare = null ) { $this->dependencyGraph = $dependencyGraph; $this->dependencyGraphComapre = $dependencyGraphCompare;