diff --git a/analyse.php b/analyse.php deleted file mode 100644 index dd9e191..0000000 --- a/analyse.php +++ /dev/null @@ -1,13 +0,0 @@ -add(new CognitiveMetricsCommand()); -$application->add(new HalsteadMetricsCommand()); - -$application->run(); diff --git a/bin/cognitive-analysis b/bin/cognitive-analysis index bfd62b7..8629f1b 100755 --- a/bin/cognitive-analysis +++ b/bin/cognitive-analysis @@ -1,14 +1,12 @@ #!/usr/bin/env php add(new CognitiveMetricsCommand()); -$application->add(new HalsteadMetricsCommand()); - -$application->run(); +(new Application())->run(); diff --git a/composer.json b/composer.json index f3cf98f..52852fe 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,8 @@ "nikic/php-parser": "^5.1", "symfony/console": "^7.1", "symfony/config": "^7.1", - "symfony/yaml": "^7.1" + "symfony/yaml": "^7.1", + "symfony/dependency-injection": "^7.1" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 44831ac..08d3626 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": "13449345b40d43a2819466b9c0c52650", + "content-hash": "66b078c5c8d9a33a83c5ad72ce006f9b", "packages": [ { "name": "nikic/php-parser", - "version": "v5.1.0", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", + "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", "shasum": "" }, "require": { @@ -60,9 +60,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.2.0" }, - "time": "2024-07-01T20:03:41+00:00" + "time": "2024-09-15T16:40:33+00:00" }, { "name": "psr/container", @@ -194,16 +194,16 @@ }, { "name": "symfony/console", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9" + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", - "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", + "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee", + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee", "shasum": "" }, "require": { @@ -267,7 +267,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.3" + "source": "https://github.com/symfony/console/tree/v7.1.5" }, "funding": [ { @@ -283,7 +283,87 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:41:01+00:00" + "time": "2024-09-20T08:28:38+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v7.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "38465f925ec4e0707b090e9147c65869837d639d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/38465f925ec4e0707b090e9147c65869837d639d", + "reference": "38465f925ec4e0707b090e9147c65869837d639d", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^3.5", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "symfony/config": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v7.1.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -354,16 +434,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c" + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a", + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a", "shasum": "" }, "require": { @@ -400,7 +480,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.1.2" + "source": "https://github.com/symfony/filesystem/tree/v7.1.5" }, "funding": [ { @@ -416,24 +496,24 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-09-17T09:16:35+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -479,7 +559,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -495,24 +575,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", + "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" @@ -557,7 +637,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -573,24 +653,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "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" @@ -638,7 +718,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -654,24 +734,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -718,7 +798,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -734,7 +814,7 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/service-contracts", @@ -821,16 +901,16 @@ }, { "name": "symfony/string", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ea272a882be7f20cad58d5d78c215001617b7f07" + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07", - "reference": "ea272a882be7f20cad58d5d78c215001617b7f07", + "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306", + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306", "shasum": "" }, "require": { @@ -888,7 +968,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.3" + "source": "https://github.com/symfony/string/tree/v7.1.5" }, "funding": [ { @@ -904,20 +984,96 @@ "type": "tidelift" } ], - "time": "2024-07-22T10:25:37+00:00" + "time": "2024-09-20T08:28:38+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v7.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "b80a669a2264609f07f1667f891dbfca25eba44c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b80a669a2264609f07f1667f891dbfca25eba44c", + "reference": "b80a669a2264609f07f1667f891dbfca25eba44c", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.1.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-28T08:00:31+00:00" }, { "name": "symfony/yaml", - "version": "v7.1.1", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "fa34c77015aa6720469db7003567b9f772492bf2" + "reference": "4e561c316e135e053bd758bf3b3eb291d9919de4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/fa34c77015aa6720469db7003567b9f772492bf2", - "reference": "fa34c77015aa6720469db7003567b9f772492bf2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4e561c316e135e053bd758bf3b3eb291d9919de4", + "reference": "4e561c316e135e053bd758bf3b3eb291d9919de4", "shasum": "" }, "require": { @@ -959,7 +1115,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.1.1" + "source": "https://github.com/symfony/yaml/tree/v7.1.5" }, "funding": [ { @@ -975,7 +1131,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-17T12:49:58+00:00" } ], "packages-dev": [ @@ -1069,26 +1225,26 @@ }, { "name": "composer/pcre", - "version": "3.2.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90" + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90", + "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "conflict": { - "phpstan/phpstan": "<1.11.8" + "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "phpstan/phpstan": "^1.11.8", + "phpstan/phpstan": "^1.11.10", "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "^8 || ^9" }, @@ -1128,7 +1284,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.2.0" + "source": "https://github.com/composer/pcre/tree/3.3.1" }, "funding": [ { @@ -1144,7 +1300,7 @@ "type": "tidelift" } ], - "time": "2024-07-25T09:36:02+00:00" + "time": "2024-08-27T18:44:43+00:00" }, { "name": "composer/xdebug-handler", @@ -1214,16 +1370,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" + "reference": "8520451a140d3f46ac33042715115e290cf5785f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", "shasum": "" }, "require": { @@ -1263,7 +1419,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" }, "funding": [ { @@ -1271,7 +1427,7 @@ "type": "github" } ], - "time": "2024-02-07T09:43:46+00:00" + "time": "2024-08-06T10:04:20+00:00" }, { "name": "infection/abstract-testframework-adapter", @@ -2103,16 +2259,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.10", + "version": "1.12.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f" + "reference": "ffa517cb918591b93acc9b95c0bebdcd0e4538bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/640410b32995914bde3eed26fa89552f9c2c082f", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ffa517cb918591b93acc9b95c0bebdcd0e4538bd", + "reference": "ffa517cb918591b93acc9b95c0bebdcd0e4538bd", "shasum": "" }, "require": { @@ -2157,36 +2313,36 @@ "type": "github" } ], - "time": "2024-08-08T09:02:50+00:00" + "time": "2024-09-19T07:58:01+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "11.0.5", + "version": "11.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "19b6365ab8b59a64438c0c3f4241feeb480c9861" + "reference": "ebdffc9e09585dafa71b9bffcdb0a229d4704c45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/19b6365ab8b59a64438c0c3f4241feeb480c9861", - "reference": "19b6365ab8b59a64438c0c3f4241feeb480c9861", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ebdffc9e09585dafa71b9bffcdb0a229d4704c45", + "reference": "ebdffc9e09585dafa71b9bffcdb0a229d4704c45", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.0", + "nikic/php-parser": "^5.1.0", "php": ">=8.2", - "phpunit/php-file-iterator": "^5.0", - "phpunit/php-text-template": "^4.0", - "sebastian/code-unit-reverse-lookup": "^4.0", - "sebastian/complexity": "^4.0", - "sebastian/environment": "^7.0", - "sebastian/lines-of-code": "^3.0", - "sebastian/version": "^5.0", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.0", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.1", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { "phpunit/phpunit": "^11.0" @@ -2198,7 +2354,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "11.0-dev" + "dev-main": "11.0.x-dev" } }, "autoload": { @@ -2227,7 +2383,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/11.0.5" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.6" }, "funding": [ { @@ -2235,20 +2391,20 @@ "type": "github" } ], - "time": "2024-07-03T05:05:37+00:00" + "time": "2024-08-22T04:37:56+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.0.1", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6ed896bf50bbbfe4d504a33ed5886278c78e4a26" + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6ed896bf50bbbfe4d504a33ed5886278c78e4a26", - "reference": "6ed896bf50bbbfe4d504a33ed5886278c78e4a26", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", "shasum": "" }, "require": { @@ -2288,7 +2444,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" }, "funding": [ { @@ -2296,7 +2452,7 @@ "type": "github" } ], - "time": "2024-07-03T05:06:37+00:00" + "time": "2024-08-27T05:02:59+00:00" }, { "name": "phpunit/php-invoker", @@ -2484,16 +2640,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.3.0", + "version": "11.3.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a8dce73a8938dfec7ac0daa91bdbcaae7d7188a3" + "reference": "d62c45a19c665bb872c2a47023a0baf41a98bb2b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a8dce73a8938dfec7ac0daa91bdbcaae7d7188a3", - "reference": "a8dce73a8938dfec7ac0daa91bdbcaae7d7188a3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d62c45a19c665bb872c2a47023a0baf41a98bb2b", + "reference": "d62c45a19c665bb872c2a47023a0baf41a98bb2b", "shasum": "" }, "require": { @@ -2507,20 +2663,20 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.5", - "phpunit/php-file-iterator": "^5.0.1", + "phpunit/php-code-coverage": "^11.0.6", + "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", "sebastian/code-unit": "^3.0.1", - "sebastian/comparator": "^6.0.1", + "sebastian/comparator": "^6.1.0", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.0", "sebastian/exporter": "^6.1.3", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", - "sebastian/type": "^5.0.1", + "sebastian/type": "^5.1.0", "sebastian/version": "^5.0.1" }, "suggest": { @@ -2564,7 +2720,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.3.0" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.3.6" }, "funding": [ { @@ -2580,20 +2736,20 @@ "type": "tidelift" } ], - "time": "2024-08-02T03:56:43+00:00" + "time": "2024-09-19T10:54:28+00:00" }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -2628,9 +2784,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "roave/security-advisories", @@ -2638,12 +2794,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "a143e7459e3961149eb6a8eecc98dfa19799d02a" + "reference": "4d2e39c44028ba729fe50efdf731d3d2ede4046b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/a143e7459e3961149eb6a8eecc98dfa19799d02a", - "reference": "a143e7459e3961149eb6a8eecc98dfa19799d02a", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/4d2e39c44028ba729fe50efdf731d3d2ede4046b", + "reference": "4d2e39c44028ba729fe50efdf731d3d2ede4046b", "shasum": "" }, "conflict": { @@ -2681,7 +2837,7 @@ "athlon1600/php-proxy-app": "<=3", "austintoddj/canvas": "<=3.4.2", "auth0/wordpress": "<=4.6", - "automad/automad": "<=2.0.0.0-alpha5", + "automad/automad": "<2.0.0.0-alpha5", "automattic/jetpack": "<9.8", "awesome-support/awesome-support": "<=6.0.7", "aws/aws-sdk-php": "<3.288.1", @@ -2740,21 +2896,23 @@ "codeigniter4/shield": "<1.0.0.0-beta8", "codiad/codiad": "<=2.8.4", "composer/composer": "<1.10.27|>=2,<2.2.24|>=2.3,<2.7.7", - "concrete5/concrete5": "<9.3.3", + "concrete5/concrete5": "<9.3.4", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", "contao/contao": ">=3,<3.5.37|>=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", "contao/core": "<3.5.39", - "contao/core-bundle": "<4.13.40|>=5,<5.3.4", + "contao/core-bundle": "<4.13.49|>=5,<5.3.15|>=5.4,<5.4.3", "contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8", "contao/managed-edition": "<=1.5", "corveda/phpsandbox": "<1.3.5", "cosenary/instagram": "<=2.3", - "craftcms/cms": "<4.6.2|>=5.0.0.0-beta1,<=5.2.2", + "craftcms/cms": "<4.6.2|>=5,<=5.2.2", "croogo/croogo": "<4", "cuyz/valinor": "<0.12", + "czim/file-handling": "<1.5|>=2,<2.3", "czproject/git-php": "<4.0.3", + "damienharper/auditor-bundle": "<5.2.6", "dapphp/securimage": "<3.6.6", "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", @@ -2779,8 +2937,9 @@ "dolibarr/dolibarr": "<19.0.2", "dompdf/dompdf": "<2.0.4", "doublethreedigital/guest-entries": "<3.1.2", - "drupal/core": ">=6,<6.38|>=7,<7.96|>=8,<10.1.8|>=10.2,<10.2.2", - "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", + "drupal/core": ">=6,<6.38|>=7,<7.96|>=8,<=11.0.4", + "drupal/core-recommended": ">=8,<=11.0.4", + "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.80|>=8,<=11.0.4", "duncanmcclean/guest-entries": "<3.1.2", "dweeves/magmi": "<=0.7.24", "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2", @@ -2809,7 +2968,7 @@ "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", "ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35", "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", - "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev", + "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev|>=3.3,<3.3.40", "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", "ezsystems/ezplatform-user": ">=1,<1.0.1", "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31", @@ -2854,7 +3013,7 @@ "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", "froala/wysiwyg-editor": "<3.2.7|>=4.0.1,<=4.1.3", - "froxlor/froxlor": "<2.1.9", + "froxlor/froxlor": "<=2.2.0.0-RC3", "frozennode/administrator": "<=5.0.12", "fuel/core": "<1.8.1", "funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3", @@ -2862,7 +3021,7 @@ "genix/cms": "<=1.1.11", "getformwork/formwork": "<1.13.1|==2.0.0.0-beta1", "getgrav/grav": "<1.7.46", - "getkirby/cms": "<4.1.1", + "getkirby/cms": "<=3.6.6.5|>=3.7,<=3.7.5.4|>=3.8,<=3.8.4.3|>=3.9,<=3.9.8.1|>=3.10,<=3.10.1|>=4,<=4.3", "getkirby/kirby": "<=2.5.12", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", @@ -2890,6 +3049,7 @@ "hyn/multi-tenant": ">=5.6,<5.7.2", "ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6.0.0-beta1,<4.6.9", "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2", + "ibexa/fieldtype-richtext": ">=4.6,<4.6.10", "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", "ibexa/post-install": "<=1.0.4", "ibexa/solr": ">=4.5,<4.5.4", @@ -2908,6 +3068,7 @@ "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.2.3", "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", + "in2code/powermail": "<7.5.1|>=8,<8.5.1|>=9,<10.9.1|>=11,<12.4.1", "innologi/typo3-appointments": "<2.0.6", "intelliants/subrion": "<4.2.2", "inter-mediator/inter-mediator": "==5.5", @@ -2937,7 +3098,7 @@ "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3", - "kimai/kimai": "<2.16", + "kimai/kimai": "<=2.20.1", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<=1.4.2", @@ -2970,7 +3131,7 @@ "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": "<2.4.5|==2.4.5|>=2.4.5.0-patch1,<2.4.5.0-patch8|==2.4.6|>=2.4.6.0-patch1,<2.4.6.0-patch6|==2.4.7", + "magento/community-edition": "<2.4.5|==2.4.5|>=2.4.5.0-patch1,<2.4.5.0-patch9|==2.4.6|>=2.4.6.0-patch1,<2.4.6.0-patch7|==2.4.7|>=2.4.7.0-patch1,<2.4.7.0-patch2", "magento/core": "<=1.9.4.5", "magento/magento1ce": "<1.9.4.3-dev", "magento/magento1ee": ">=1,<1.14.4.3-dev", @@ -2981,7 +3142,8 @@ "mantisbt/mantisbt": "<2.26.2", "marcwillmann/turn": "<0.3.3", "matyhtf/framework": "<3.0.6", - "mautic/core": "<4.4.12|>=5.0.0.0-alpha,<5.0.4", + "mautic/core": "<4.4.13|>=5,<5.1.1", + "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", "mdanter/ecc": "<2", "mediawiki/core": "<1.36.2", "mediawiki/matomo": "<2.4.3", @@ -3016,6 +3178,7 @@ "munkireport/softwareupdate": "<1.6", "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", + "nategood/httpful": "<1", "neoan3-apps/template": "<1.1.1", "neorazorx/facturascripts": "<2022.04", "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", @@ -3090,7 +3253,7 @@ "phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5", "phpoffice/common": "<0.2.9", "phpoffice/phpexcel": "<1.8", - "phpoffice/phpspreadsheet": "<1.16", + "phpoffice/phpspreadsheet": "<1.29.1|>=2,<2.1.1|>=2.2,<2.2.1", "phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36", "phpservermon/phpservermon": "<3.6", "phpsysinfo/phpsysinfo": "<3.4.3", @@ -3099,9 +3262,10 @@ "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", "pi/pi": "<=2.5", - "pimcore/admin-ui-classic-bundle": "<=1.5.1", + "pimcore/admin-ui-classic-bundle": "<1.5.4", "pimcore/customer-management-framework-bundle": "<4.0.6", "pimcore/data-hub": "<1.2.4", + "pimcore/data-importer": "<1.8.9|>=1.9,<1.9.3", "pimcore/demo": "<10.3", "pimcore/ecommerce-framework-bundle": "<1.0.10", "pimcore/perspective-editor": "<1.5.1", @@ -3132,7 +3296,7 @@ "pubnub/pubnub": "<6.1", "pusher/pusher-php-server": "<2.2.1", "pwweb/laravel-core": "<=0.3.6.0-beta", - "pxlrbt/filament-excel": "<2.3.3", + "pxlrbt/filament-excel": "<1.1.14|>=2.0.0.0-alpha,<2.3.3", "pyrocms/pyrocms": "<=3.9.1", "qcubed/qcubed": "<=3.1.1", "quickapps/cms": "<=2.0.0.0-beta2", @@ -3283,7 +3447,7 @@ "tinymighty/wiki-seo": "<1.2.2", "titon/framework": "<9.9.99", "tobiasbg/tablepress": "<=2.0.0.0-RC1", - "topthink/framework": "<6.0.17|>=6.1,<6.1.5|>=8,<8.0.4", + "topthink/framework": "<6.0.17|>=6.1,<=8.0.4", "topthink/think": "<=6.1.1", "topthink/thinkphp": "<=3.2.3", "torrentpier/torrentpier": "<=2.4.3", @@ -3292,7 +3456,7 @@ "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", "twbs/bootstrap": "<=3.4.1|>=4,<=4.6.2", - "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", + "twig/twig": "<1.44.8|>=2,<2.16.1|>=3,<3.11.1|>=3.12,<3.14", "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/cms-core": "<=8.7.56|>=9,<=9.5.47|>=10,<=10.4.44|>=11,<=11.5.36|>=12,<=12.4.14|>=13,<=13.1", @@ -3344,6 +3508,7 @@ "winter/wn-dusk-plugin": "<2.1", "winter/wn-system-module": "<1.2.4", "wintercms/winter": "<=1.2.3", + "wireui/wireui": "<1.19.3|>=2,<2.1.3", "woocommerce/woocommerce": "<6.6|>=8.8,<8.8.5|>=8.9,<8.9.3", "wp-cli/wp-cli": ">=0.12,<2.5", "wp-graphql/wp-graphql": "<=1.14.5", @@ -3446,7 +3611,7 @@ "type": "tidelift" } ], - "time": "2024-08-12T19:04:53+00:00" + "time": "2024-09-23T20:04:53+00:00" }, { "name": "sanmai/later", @@ -3749,16 +3914,16 @@ }, { "name": "sebastian/comparator", - "version": "6.0.2", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "450d8f237bd611c45b5acf0733ce43e6bb280f81" + "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/450d8f237bd611c45b5acf0733ce43e6bb280f81", - "reference": "450d8f237bd611c45b5acf0733ce43e6bb280f81", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa37b9e2ca618cb051d71b60120952ee8ca8b03d", + "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d", "shasum": "" }, "require": { @@ -3769,12 +3934,12 @@ "sebastian/exporter": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -3814,7 +3979,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.1.0" }, "funding": [ { @@ -3822,7 +3987,7 @@ "type": "github" } ], - "time": "2024-08-12T06:07:25+00:00" + "time": "2024-09-11T15:42:56+00:00" }, { "name": "sebastian/complexity", @@ -4391,28 +4556,28 @@ }, { "name": "sebastian/type", - "version": "5.0.1", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fb6a6566f9589e86661291d13eba708cce5eb4aa" + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb6a6566f9589e86661291d13eba708cce5eb4aa", - "reference": "fb6a6566f9589e86661291d13eba708cce5eb4aa", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/461b9c5da241511a2a0e8f240814fb23ce5c0aac", + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -4436,7 +4601,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/type/issues", "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/type/tree/5.1.0" }, "funding": [ { @@ -4444,7 +4609,7 @@ "type": "github" } ], - "time": "2024-07-03T05:11:49+00:00" + "time": "2024-09-17T13:12:04+00:00" }, { "name": "sebastian/version", @@ -4502,16 +4667,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.10.2", + "version": "3.10.3", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/62d32998e820bddc40f99f8251958aed187a5c9c", + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c", "shasum": "" }, "require": { @@ -4578,100 +4743,20 @@ "type": "open_collective" } ], - "time": "2024-07-21T23:26:44+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v7.1.3", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "8126f0be4ff984e4db0140e60917900a53facb49" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8126f0be4ff984e4db0140e60917900a53facb49", - "reference": "8126f0be4ff984e4db0140e60917900a53facb49", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/service-contracts": "^3.5", - "symfony/var-exporter": "^6.4|^7.0" - }, - "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<6.4", - "symfony/finder": "<6.4", - "symfony/yaml": "<6.4" - }, - "provide": { - "psr/container-implementation": "1.1|2.0", - "symfony/service-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "symfony/config": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows you to standardize and centralize the way objects are constructed in your application", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.1.3" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-07-26T07:35:39+00:00" + "time": "2024-09-18T10:38:58+00:00" }, { "name": "symfony/finder", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "717c6329886f32dc65e27461f80f2a465412fdca" + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/717c6329886f32dc65e27461f80f2a465412fdca", - "reference": "717c6329886f32dc65e27461f80f2a465412fdca", + "url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823", + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823", "shasum": "" }, "require": { @@ -4706,7 +4791,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.1.3" + "source": "https://github.com/symfony/finder/tree/v7.1.4" }, "funding": [ { @@ -4722,20 +4807,20 @@ "type": "tidelift" } ], - "time": "2024-07-24T07:08:44+00:00" + "time": "2024-08-13T14:28:19+00:00" }, { "name": "symfony/process", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca" + "reference": "5c03ee6369281177f07f7c68252a280beccba847" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca", + "url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847", + "reference": "5c03ee6369281177f07f7c68252a280beccba847", "shasum": "" }, "require": { @@ -4767,7 +4852,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.3" + "source": "https://github.com/symfony/process/tree/v7.1.5" }, "funding": [ { @@ -4783,20 +4868,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:44:47+00:00" + "time": "2024-09-19T21:48:23+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "86af4617cca75a6e28598f49ae0690f3b9d4591f" + "reference": "e20e03889539fd4e4211e14d2179226c513c010d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/86af4617cca75a6e28598f49ae0690f3b9d4591f", - "reference": "86af4617cca75a6e28598f49ae0690f3b9d4591f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e20e03889539fd4e4211e14d2179226c513c010d", + "reference": "e20e03889539fd4e4211e14d2179226c513c010d", "shasum": "" }, "require": { @@ -4850,83 +4935,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.1.3" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-07-26T12:41:01+00:00" - }, - { - "name": "symfony/var-exporter", - "version": "v7.1.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-exporter.git", - "reference": "b80a669a2264609f07f1667f891dbfca25eba44c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b80a669a2264609f07f1667f891dbfca25eba44c", - "reference": "b80a669a2264609f07f1667f891dbfca25eba44c", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\VarExporter\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows exporting any serializable PHP data structure to plain PHP code", - "homepage": "https://symfony.com", - "keywords": [ - "clone", - "construct", - "export", - "hydrate", - "instantiate", - "lazy-loading", - "proxy", - "serialize" - ], - "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.1.2" + "source": "https://github.com/symfony/var-dumper/tree/v7.1.5" }, "funding": [ { @@ -4942,7 +4951,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T08:00:31+00:00" + "time": "2024-09-16T10:07:02+00:00" }, { "name": "thecodingmachine/safe", diff --git a/readme.md b/readme.md index 1b1c102..882e553 100644 --- a/readme.md +++ b/readme.md @@ -11,25 +11,25 @@ Cognitive Code Analysis is an approach to understanding and improving code by fo Cognitive Complexity Analysis ```bash -php analyse.php metrics:cognitive +bin/cognitive-analysis metrics:cognitive ``` Generate a report, supported types are `json`, `csv`, `html`. ```bash -php analyse.php metrics:cognitive --report-type json --report-file cognitive.json +bin/cognitive-analysis metrics:cognitive --report-type json --report-file cognitive.json ``` You can also pass a baseline file to compare the results to. The JSON report is used as baseline. The output will now show a delta if a value was changed. ```bash -php analyse.php metrics:cognitive --baseline cognitive.json +bin/cognitive-analysis metrics:cognitive --baseline cognitive.json ``` Halstead Complexity Analysis ```bash -php analyse.php metrics:halstead +bin/cognitive-analysis metrics:halstead ``` ## Documentation diff --git a/src/Application.php b/src/Application.php new file mode 100644 index 0000000..5c45059 --- /dev/null +++ b/src/Application.php @@ -0,0 +1,167 @@ +containerBuilder = new ContainerBuilder(); + $this->bootstrap(); + } + + private function registerServices(): void + { + $this->containerBuilder->register(HalsteadMetricsCollector::class, HalsteadMetricsCollector::class) + ->setPublic(true); + + $this->containerBuilder->register(CognitiveMetricsCollector::class, CognitiveMetricsCollector::class) + ->setPublic(true); + + $this->containerBuilder->register(ScoreCalculator::class, ScoreCalculator::class) + ->setPublic(true); + + $this->containerBuilder->register(ConfigService::class, ConfigService::class) + ->setPublic(true); + + $this->containerBuilder->register(HalsteadMetricTextRenderer::class, HalsteadMetricTextRenderer::class) + ->setPublic(true); + + $this->containerBuilder->register(CognitiveMetricTextRenderer::class, CognitiveMetricTextRenderer::class) + ->setPublic(true); + + $this->containerBuilder->register(BaselineService::class, BaselineService::class) + ->setPublic(true); + + $this->containerBuilder->register(Processor::class, Processor::class) + ->setPublic(true); + + $this->containerBuilder->register(ConfigLoader::class, ConfigLoader::class) + ->setPublic(true); + + $this->containerBuilder->register(ParserFactory::class, ParserFactory::class) + ->setPublic(true); + + $this->containerBuilder->register(DirectoryScanner::class, DirectoryScanner::class) + ->setPublic(true); + + $this->containerBuilder->register(NodeTraverserInterface::class, NodeTraverser::class) + ->setPublic(true); + } + + private function bootstrap(): void + { + $this->registerServices(); + $this->bootstrapMetricsCollectors(); + $this->configureConfigService(); + $this->registerMetricsFacade(); + $this->registerCommands(); + $this->configureApplication(); + } + + private function bootstrapMetricsCollectors(): void + { + $this->containerBuilder->register(CognitiveMetricsCollector::class, CognitiveMetricsCollector::class) + ->setArguments([ + new Reference(ParserFactory::class), + new Reference(NodeTraverserInterface::class), + new Reference(DirectoryScanner::class), + ]) + ->setPublic(true); + + $this->containerBuilder->register(HalsteadMetricsCollector::class, HalsteadMetricsCollector::class) + ->setArguments([ + new Reference(ParserFactory::class), + new Reference(NodeTraverserInterface::class), + new Reference(DirectoryScanner::class), + ]) + ->setPublic(true); + } + + private function configureConfigService(): void + { + $this->containerBuilder->register(ConfigService::class, ConfigService::class) + ->setArguments([ + new Reference(Processor::class), + new Reference(ConfigLoader::class), + ]) + ->setPublic(true); + } + + private function registerMetricsFacade(): void + { + $this->containerBuilder->register(MetricsFacade::class, MetricsFacade::class) + ->setArguments([ + new Reference(HalsteadMetricsCollector::class), + new Reference(CognitiveMetricsCollector::class), + new Reference(ScoreCalculator::class), + new Reference(ConfigService::class), + ]) + ->setPublic(true); + } + + private function registerCommands(): void + { + $this->containerBuilder->register(CognitiveMetricsCommand::class, CognitiveMetricsCommand::class) + ->setArguments([ + new Reference(MetricsFacade::class), + new Reference(CognitiveMetricTextRenderer::class), + new Reference(BaselineService::class), + ]) + ->setPublic(true); + + $this->containerBuilder->register(HalsteadMetricsCommand::class, HalsteadMetricsCommand::class) + ->setArguments([ + new Reference(MetricsFacade::class), + new Reference(HalsteadMetricTextRenderer::class), + ]) + ->setPublic(true); + } + + private function configureApplication(): void + { + $this->containerBuilder->register(SymfonyApplication::class, SymfonyApplication::class) + ->setPublic(true) + ->addMethodCall('add', [new Reference(CognitiveMetricsCommand::class)]) + ->addMethodCall('add', [new Reference(HalsteadMetricsCommand::class)]); + } + + public function run(): void + { + $application = $this->containerBuilder->get(SymfonyApplication::class); + // @phpstan-ignore-next-line + $application->run(); + } + + public function get(string $id): mixed + { + return $this->containerBuilder->get($id); + } +} diff --git a/src/Business/AbstractMetricCollector.php b/src/Business/AbstractMetricCollector.php index 5391076..c5ed599 100644 --- a/src/Business/AbstractMetricCollector.php +++ b/src/Business/AbstractMetricCollector.php @@ -6,7 +6,6 @@ use Generator; use PhpParser\Error; -use PhpParser\NodeTraverser; use PhpParser\NodeTraverserInterface; use PhpParser\Parser; use PhpParser\ParserFactory; @@ -19,8 +18,6 @@ abstract class AbstractMetricCollector { protected Parser $parser; - protected NodeTraverserInterface $traverser; - protected DirectoryScanner $directoryScanner; /** * @param array $config @@ -35,11 +32,12 @@ protected function getExcludePatternsFromConfig(array $config): array return []; } - public function __construct() - { - $this->parser = (new ParserFactory())->createForHostVersion(); - $this->traverser = new NodeTraverser(); - $this->directoryScanner = new DirectoryScanner(); + public function __construct( + protected readonly ParserFactory $parserFactory, + protected readonly NodeTraverserInterface $traverser, + protected readonly DirectoryScanner $directoryScanner + ) { + $this->parser = $this->parserFactory->createForHostVersion(); } /** diff --git a/src/Business/Cognitive/BaselineService.php b/src/Business/Cognitive/BaselineService.php new file mode 100644 index 0000000..b82a5fe --- /dev/null +++ b/src/Business/Cognitive/BaselineService.php @@ -0,0 +1,54 @@ +> $baseline + */ + public function calculateDeltas(CognitiveMetricsCollection $metricsCollection, array $baseline): void + { + foreach ($baseline as $class => $data) { + foreach ($data['methods'] as $methodName => $methodData) { + $metrics = $metricsCollection->getClassWithMethod($class, $methodName); + if (!$metrics) { + continue; + } + + $previousMetrics = CognitiveMetrics::fromArray($methodData); + $metrics->calculateDeltas($previousMetrics); + } + } + } + + + /** + * Loads the baseline file and returns the data as an array. + * + * @param string $baselineFile + * @return array> $baseline + * @throws \JsonException + */ + public function loadBaseline(string $baselineFile): array + { + if (!file_exists($baselineFile)) { + throw new RuntimeException('Baseline file does not exist.'); + } + + $baseline = file_get_contents($baselineFile); + if ($baseline === false) { + throw new RuntimeException('Failed to read baseline file.'); + } + + return json_decode($baseline, true, 512, JSON_THROW_ON_ERROR); + } +} diff --git a/src/Business/Cognitive/CognitiveMetrics.php b/src/Business/Cognitive/CognitiveMetrics.php index ca2d1a3..ccdc545 100644 --- a/src/Business/Cognitive/CognitiveMetrics.php +++ b/src/Business/Cognitive/CognitiveMetrics.php @@ -12,8 +12,23 @@ */ class CognitiveMetrics implements JsonSerializable { - private string $class = ''; - private string $method = ''; + /** + * @var array + */ + private array $metrics = [ + 'lineCount', + 'argCount', + 'returnCount', + 'variableCount', + 'propertyCallCount', + 'ifCount', + 'ifNestingLevel', + 'elseCount' + ]; + + private string $class; + private string $method; + private int $lineCount = 0; private int $argCount = 0; private int $returnCount = 0; @@ -33,6 +48,15 @@ class CognitiveMetrics implements JsonSerializable private float $elseCountWeight = 0.0; private float $score = 0.0; + private ?Delta $lineCountWeightDelta = null; + private ?Delta $argCountWeightDelta = null; + private ?Delta $returnCountWeightDelta = null; + private ?Delta $variableCountWeightDelta = null; + private ?Delta $propertyCallCountWeightDelta = null; + private ?Delta $ifCountWeightDelta = null; + private ?Delta $ifNestingLevelWeightDelta = null; + private ?Delta $elseCountWeightDelta = null; + /** * @param array $metrics */ @@ -40,25 +64,70 @@ public function __construct(array $metrics) { $this->assertArrayKeyIsPresent($metrics, 'class'); $this->assertArrayKeyIsPresent($metrics, 'method'); - $this->assertArrayKeyIsPresent($metrics, 'line_count'); - $this->assertArrayKeyIsPresent($metrics, 'arg_count'); - $this->assertArrayKeyIsPresent($metrics, 'return_count'); - $this->assertArrayKeyIsPresent($metrics, 'variable_count'); - $this->assertArrayKeyIsPresent($metrics, 'property_call_count'); - $this->assertArrayKeyIsPresent($metrics, 'if_count'); - $this->assertArrayKeyIsPresent($metrics, 'if_nesting_level'); - $this->assertArrayKeyIsPresent($metrics, 'else_count'); - - $this->class = $metrics['class']; $this->method = $metrics['method']; - $this->lineCount = $metrics['line_count']; - $this->argCount = $metrics['arg_count']; - $this->returnCount = $metrics['return_count']; - $this->variableCount = $metrics['variable_count']; - $this->propertyCallCount = $metrics['property_call_count']; - $this->ifCount = $metrics['if_count']; - $this->ifNestingLevel = $metrics['if_nesting_level']; - $this->elseCount = $metrics['else_count']; + $this->class = $metrics['class']; + + $this->setRequiredMetricProperties($metrics); + $this->setOptionalMetricProperties($metrics); + } + + /** + * @param array $metrics + * @return void + */ + private function setRequiredMetricProperties(array $metrics): void + { + foreach ($this->metrics as $metricName) { + $this->assertArrayKeyIsPresent($metrics, $metricName); + $this->$metricName = $metrics[$metricName]; + } + } + + /** + * @param array $metrics + * @return void + */ + private function setOptionalMetricProperties(array $metrics): void + { + foreach ($this->metrics as $metricName) { + $property = $metricName . 'Weight'; + if (array_key_exists($property, $metrics)) { + $this->$property = $metrics[$property]; + } + } + } + + private function assertSame(self $other): void + { + if ($this->equals($other)) { + return; + } + + throw new InvalidArgumentException(sprintf( + 'Cannot calculate deltas for different methods: %s::%s and %s::%s', + $this->getClass(), + $this->getMethod(), + $other->getClass(), + $other->getMethod( + ) + )); + } + + /** + * Calculate delta between current instance and another instance of CognitiveMetrics. + */ + public function calculateDeltas(self $other): void + { + $this->assertSame($other); + + $this->lineCountWeightDelta = new Delta($other->getLineCountWeight(), $this->lineCountWeight); + $this->argCountWeightDelta = new Delta($other->getArgCountWeight(), $this->argCountWeight); + $this->returnCountWeightDelta = new Delta($other->getReturnCountWeight(), $this->returnCountWeight); + $this->variableCountWeightDelta = new Delta($other->getVariableCountWeight(), $this->variableCountWeight); + $this->propertyCallCountWeightDelta = new Delta($other->getPropertyCallCountWeight(), $this->propertyCallCountWeight); + $this->ifCountWeightDelta = new Delta($other->getIfCountWeight(), $this->ifCountWeight); + $this->ifNestingLevelWeightDelta = new Delta($other->getIfNestingLevelWeight(), $this->ifNestingLevelWeight); + $this->elseCountWeightDelta = new Delta($other->getElseCountWeight(), $this->elseCountWeight); } /** @@ -133,7 +202,6 @@ public function getElseCount(): int return $this->elseCount; } - // Getters and setters for weight attributes public function getLineCountWeight(): float { return $this->lineCountWeight; @@ -224,6 +292,46 @@ public function getScore(): float return $this->score; } + public function getLineCountWeightDelta(): ?Delta + { + return $this->lineCountWeightDelta; + } + + public function getArgCountWeightDelta(): ?Delta + { + return $this->argCountWeightDelta; + } + + public function getReturnCountWeightDelta(): ?Delta + { + return $this->returnCountWeightDelta; + } + + public function getVariableCountWeightDelta(): ?Delta + { + return $this->variableCountWeightDelta; + } + + public function getPropertyCallCountWeightDelta(): ?Delta + { + return $this->propertyCallCountWeightDelta; + } + + public function getIfCountWeightDelta(): ?Delta + { + return $this->ifCountWeightDelta; + } + + public function getIfNestingLevelWeightDelta(): ?Delta + { + return $this->ifNestingLevelWeightDelta; + } + + public function getElseCountWeightDelta(): ?Delta + { + return $this->elseCountWeightDelta; + } + public function equals(self $metrics): bool { return $metrics->getClass() === $this->class @@ -238,22 +346,30 @@ public function toArray(): array return [ 'class' => $this->class, 'method' => $this->method, - 'line_count' => $this->lineCount, - 'arg_count' => $this->argCount, - 'return_count' => $this->returnCount, - 'variable_count' => $this->variableCount, - 'property_call_count' => $this->propertyCallCount, - 'if_count' => $this->ifCount, - 'if_nesting_level' => $this->ifNestingLevel, - 'else_count' => $this->elseCount, - 'line_count_weight' => $this->lineCountWeight, - 'arg_count_weight' => $this->argCountWeight, - 'return_count_weight' => $this->returnCountWeight, - 'variable_count_weight' => $this->variableCountWeight, - 'property_call_count_weight' => $this->propertyCallCountWeight, - 'if_count_weight' => $this->ifCountWeight, - 'if_nesting_level_weight' => $this->ifNestingLevelWeight, - 'else_count_weight' => $this->elseCountWeight, + 'lineCount' => $this->lineCount, + 'argCount' => $this->argCount, + 'returnCount' => $this->returnCount, + 'variableCount' => $this->variableCount, + 'propertyCallCount' => $this->propertyCallCount, + 'ifCount' => $this->ifCount, + 'ifNestingLevel' => $this->ifNestingLevel, + 'elseCount' => $this->elseCount, + 'lineCountWeight' => $this->lineCountWeight, + 'argCountWeight' => $this->argCountWeight, + 'returnCountWeight' => $this->returnCountWeight, + 'variableCountWeight' => $this->variableCountWeight, + 'propertyCallCountWeight' => $this->propertyCallCountWeight, + 'ifCountWeight' => $this->ifCountWeight, + 'ifNestingLevelWeight' => $this->ifNestingLevelWeight, + 'elseCountWeight' => $this->elseCountWeight, + 'lineCountWeightDelta' => $this->lineCountWeightDelta, + 'argCountWeightDelta' => $this->argCountWeightDelta, + 'returnCountWeightDelta' => $this->returnCountWeightDelta, + 'variableCountWeightDelta' => $this->variableCountWeightDelta, + 'propertyCallCountWeightDelta' => $this->propertyCallCountWeightDelta, + 'ifCountWeightDelta' => $this->ifCountWeightDelta, + 'ifNestingLevelWeightDelta' => $this->ifNestingLevelWeightDelta, + 'elseCountWeightDelta' => $this->elseCountWeightDelta, ]; } diff --git a/src/Business/Cognitive/CognitiveMetricsCollection.php b/src/Business/Cognitive/CognitiveMetricsCollection.php index c0f4c81..4f26ce5 100644 --- a/src/Business/Cognitive/CognitiveMetricsCollection.php +++ b/src/Business/Cognitive/CognitiveMetricsCollection.php @@ -84,6 +84,17 @@ public function contains(CognitiveMetrics $otherMetric): bool return false; } + public function getClassWithMethod(string $class, string $method): ?CognitiveMetrics + { + foreach ($this->metrics as $metric) { + if ($metric->getClass() === $class && $metric->getMethod() === $method) { + return $metric; + } + } + + return null; + } + public function filterByClassName(string $className): CognitiveMetricsCollection { return $this->filter(function (CognitiveMetrics $metric) use ($className) { diff --git a/src/Business/Cognitive/Delta.php b/src/Business/Cognitive/Delta.php new file mode 100644 index 0000000..a0f0d1b --- /dev/null +++ b/src/Business/Cognitive/Delta.php @@ -0,0 +1,46 @@ +hasIncreased = true; + $this->difference = $after - $before; + return; + } + + $this->hasIncreased = false; + $this->difference = $after - $before; + } + + public function getValue(): float + { + return $this->difference; + } + + public function hasIncreased(): bool + { + return $this->hasIncreased; + } + + public function __toString(): string + { + return (string)$this->difference; + } + + public function hasNotChanged(): bool + { + return $this->difference === 0.0; + } +} diff --git a/src/Business/Cognitive/Exporter/JsonExporter.php b/src/Business/Cognitive/Exporter/JsonExporter.php index 0cc24b1..193c802 100644 --- a/src/Business/Cognitive/Exporter/JsonExporter.php +++ b/src/Business/Cognitive/Exporter/JsonExporter.php @@ -5,12 +5,16 @@ namespace Phauthentic\CodeQualityMetrics\Business\Cognitive\Exporter; use Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetricsCollection; +use RuntimeException; /** * */ class JsonExporter implements DataExporterInterface { + /** + * @throws \JsonException + */ public function export(CognitiveMetricsCollection $metricsCollection, string $filename): void { $jsonData = []; @@ -19,30 +23,26 @@ public function export(CognitiveMetricsCollection $metricsCollection, string $fi foreach ($groupedByClass as $class => $methods) { foreach ($methods as $metrics) { - $jsonData[] = [ + $jsonData[$class]['methods'][$metrics->getMethod()] = [ 'class' => $metrics->getClass(), - 'methods' => [ - $metrics->getMethod() => [ - 'name' => $metrics->getMethod(), - 'lineCount' => $metrics->getLineCount(), - 'lineCountWeight' => $metrics->getLineCountWeight(), - 'argCount' => $metrics->getArgCount(), - 'argCountWeight' => $metrics->getArgCountWeight(), - 'returnCount' => $metrics->getReturnCount(), - 'returnCountWeight' => $metrics->getReturnCountWeight(), - 'variableCount' => $metrics->getVariableCount(), - 'variableCountWeight' => $metrics->getVariableCountWeight(), - 'propertyCallCount' => $metrics->getPropertyCallCount(), - 'propertyCallCountWeight' => $metrics->getPropertyCallCountWeight(), - 'ifCount' => $metrics->getIfCount(), - 'ifCountWeight' => $metrics->getIfCountWeight(), - 'ifNestingLevel' => $metrics->getIfNestingLevel(), - 'ifNestingLevelWeight' => $metrics->getIfNestingLevelWeight(), - 'elseCount' => $metrics->getElseCount(), - 'elseCountWeight' => $metrics->getElseCountWeight(), - 'score' => $metrics->getScore() - ] - ] + 'method' => $metrics->getMethod(), + 'lineCount' => $metrics->getLineCount(), + 'lineCountWeight' => $metrics->getLineCountWeight(), + 'argCount' => $metrics->getArgCount(), + 'argCountWeight' => $metrics->getArgCountWeight(), + 'returnCount' => $metrics->getReturnCount(), + 'returnCountWeight' => $metrics->getReturnCountWeight(), + 'variableCount' => $metrics->getVariableCount(), + 'variableCountWeight' => $metrics->getVariableCountWeight(), + 'propertyCallCount' => $metrics->getPropertyCallCount(), + 'propertyCallCountWeight' => $metrics->getPropertyCallCountWeight(), + 'ifCount' => $metrics->getIfCount(), + 'ifCountWeight' => $metrics->getIfCountWeight(), + 'ifNestingLevel' => $metrics->getIfNestingLevel(), + 'ifNestingLevelWeight' => $metrics->getIfNestingLevelWeight(), + 'elseCount' => $metrics->getElseCount(), + 'elseCountWeight' => $metrics->getElseCountWeight(), + 'score' => $metrics->getScore() ]; } } @@ -50,7 +50,7 @@ public function export(CognitiveMetricsCollection $metricsCollection, string $fi $jsonData = json_encode($jsonData, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR); if (file_put_contents($filename, $jsonData) === false) { - throw new \RuntimeException("Unable to write to file: $filename"); + throw new RuntimeException("Unable to write to file: $filename"); } } } diff --git a/src/Business/MetricsFacade.php b/src/Business/MetricsFacade.php index f2bee2c..64317dc 100644 --- a/src/Business/MetricsFacade.php +++ b/src/Business/MetricsFacade.php @@ -19,21 +19,15 @@ */ class MetricsFacade { - private HalsteadMetricsCollector $halsteadMetricsCollector; - private CognitiveMetricsCollector $cognitiveMetricsCollector; - private ScoreCalculator $scoreCalculator; - private ConfigService $configService; - /** * Constructor initializes the metrics collectors, score calculator, and config service. */ - public function __construct() - { - $this->halsteadMetricsCollector = new HalsteadMetricsCollector(); - $this->cognitiveMetricsCollector = new CognitiveMetricsCollector(); - $this->scoreCalculator = new ScoreCalculator(); - $this->configService = new ConfigService(); - + public function __construct( + private readonly HalsteadMetricsCollector $halsteadMetricsCollector, + private readonly CognitiveMetricsCollector $cognitiveMetricsCollector, + private readonly ScoreCalculator $scoreCalculator, + private readonly ConfigService $configService + ) { $this->loadConfig(__DIR__ . '/../../config.yml'); } diff --git a/src/Command/CognitiveMetricsCommand.php b/src/Command/CognitiveMetricsCommand.php index 05f9d35..a6a0cae 100644 --- a/src/Command/CognitiveMetricsCommand.php +++ b/src/Command/CognitiveMetricsCommand.php @@ -5,6 +5,7 @@ namespace Phauthentic\CodeQualityMetrics\Command; use Exception; +use Phauthentic\CodeQualityMetrics\Business\Cognitive\BaselineService; use Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetricsCollection; use Phauthentic\CodeQualityMetrics\Business\MetricsFacade; use Phauthentic\CodeQualityMetrics\Command\Presentation\CognitiveMetricTextRenderer; @@ -32,17 +33,15 @@ class CognitiveMetricsCommand extends Command // Argument name for the path to the PHP files or directories. private const ARGUMENT_PATH = 'path'; - private MetricsFacade $metricsFacade; - private CognitiveMetricTextRenderer $metricTextRenderer; - /** * Constructor to initialize dependencies. */ - public function __construct() - { + public function __construct( + private MetricsFacade $metricsFacade, + private CognitiveMetricTextRenderer $metricTextRenderer, + private BaselineService $baselineService + ) { parent::__construct(); - $this->metricsFacade = new MetricsFacade(); - $this->metricTextRenderer = new CognitiveMetricTextRenderer(); } /** @@ -76,19 +75,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Command::FAILURE; } - // Load baseline if the option is provided. - $baseline = $this->handleBaseLine($input); - // Generate metrics for the provided path. $metricsCollection = $this->metricsFacade->getCognitiveMetrics($path); + // Load baseline if the option is provided. + $this->handleBaseLine($input, $metricsCollection); + // Handle different export options. if (!$this->handleExportOptions($input, $output, $metricsCollection)) { return Command::FAILURE; } // Render the metrics to the console. - $this->metricTextRenderer->render($metricsCollection, $baseline, $output); + $this->metricTextRenderer->render($metricsCollection, [], $output); return Command::SUCCESS; } @@ -97,39 +96,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int * Handles the baseline option and loads the baseline file if provided. * * @param InputInterface $input - * @return array> + * @param CognitiveMetricsCollection $metricsCollection * @throws Exception */ - private function handleBaseLine(InputInterface $input): array + private function handleBaseLine(InputInterface $input, CognitiveMetricsCollection $metricsCollection): void { - $baseline = []; $baselineFile = $input->getOption(self::OPTION_BASELINE); if ($baselineFile) { - $baseline = $this->loadBaseline($baselineFile); - } - - return $baseline; - } - - /** - * Loads the baseline file and returns the data as an array. - * - * @param string $baselineFile - * @return array> $baseline - * @throws \JsonException - */ - private function loadBaseline(string $baselineFile): array - { - if (!file_exists($baselineFile)) { - throw new Exception('Baseline file does not exist.'); - } - - $baseline = file_get_contents($baselineFile); - if ($baseline === false) { - throw new Exception('Failed to read baseline file.'); + $baseline = $this->baselineService->loadBaseline($baselineFile); + $this->baselineService->calculateDeltas($metricsCollection, $baseline); } - - return json_decode($baseline, true, 512, JSON_THROW_ON_ERROR); } /** diff --git a/src/Command/HalsteadMetricsCommand.php b/src/Command/HalsteadMetricsCommand.php index afc22c0..8a34f86 100644 --- a/src/Command/HalsteadMetricsCommand.php +++ b/src/Command/HalsteadMetricsCommand.php @@ -34,17 +34,14 @@ class HalsteadMetricsCommand extends Command // Argument name for the path to the PHP files or directories. private const ARGUMENT_PATH = 'path'; - private MetricsFacade $metricsFacade; - private HalsteadMetricTextRenderer $metricTextRenderer; - /** * Constructor to initialize dependencies. */ - public function __construct() - { + public function __construct( + private MetricsFacade $metricsFacade, + private HalsteadMetricTextRenderer $metricTextRenderer + ) { parent::__construct(); - $this->metricsFacade = new MetricsFacade(); - $this->metricTextRenderer = new HalsteadMetricTextRenderer(); } /** diff --git a/src/Command/Presentation/CognitiveMetricTextRenderer.php b/src/Command/Presentation/CognitiveMetricTextRenderer.php index cd2737d..98104df 100644 --- a/src/Command/Presentation/CognitiveMetricTextRenderer.php +++ b/src/Command/Presentation/CognitiveMetricTextRenderer.php @@ -6,6 +6,7 @@ use Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetrics; use Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetricsCollection; +use RuntimeException; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Output\OutputInterface; @@ -16,7 +17,7 @@ class CognitiveMetricTextRenderer { /** * @param CognitiveMetricsCollection $metricsCollection - * @param array> $baseline + * @param array> $baseline * @param OutputInterface $output */ public function render(CognitiveMetricsCollection $metricsCollection, array $baseline, OutputInterface $output): void @@ -32,7 +33,7 @@ public function render(CognitiveMetricsCollection $metricsCollection, array $bas $rows = []; foreach ($metrics as $metric) { - $row = $this->prepareTableRow($metric, $baseline); + $row = $this->prepareTableRow($metric); $rows[] = $row; } @@ -63,10 +64,9 @@ protected function getTableHeaders(): array /** * @param CognitiveMetrics $metrics - * @param array> $baseline * @return array */ - protected function prepareTableRow(CognitiveMetrics $metrics, array $baseline): array + protected function prepareTableRow(CognitiveMetrics $metrics): array { $row = [ 'methodName' => $metrics->getMethod(), @@ -95,55 +95,25 @@ protected function prepareTableRow(CognitiveMetrics $metrics, array $baseline): foreach ($keys as $key) { $getMethod = 'get' . $key; $getMethodWeight = 'get' . $key . 'Weight'; + $getDeltaMethod = 'get' . $key . 'WeightDelta'; $weight = $metrics->{$getMethodWeight}(); $row[$key] = $metrics->{$getMethod}() . ' (' . round($weight, 3) . ')'; - $row = $this->addDelta($row, $metrics, $baseline, $key, $weight); - } - - return $row; - } - /** - * @param array $row - * @param CognitiveMetrics $metrics - * @param array> $baseline - * @param string $key - * @param float $weight - * @return array - */ - private function addDelta( - array $row, - CognitiveMetrics $metrics, - array $baseline, - string $key, - float $weight - ): array { - foreach ($baseline as $classMetrics) { - if (!isset($classMetrics['class']) || $classMetrics['class'] !== $metrics->getClass()) { - continue; + if (!method_exists($metrics, $getDeltaMethod)) { + throw new RuntimeException('Method not found: ' . $getDeltaMethod); } - if (!isset($classMetrics['methods'][$metrics->getMethod()])) { + $delta = $metrics->{$getDeltaMethod}(); + if ($delta === null || $delta->hasNotChanged()) { continue; } - $method = $key . 'Weight'; - if (!isset($classMetrics['methods'][$metrics->getMethod()][$method])) { + if ($delta->hasIncreased()) { + $row[$key] .= PHP_EOL . 'Δ +' . round($delta->getValue(), 3) . ''; continue; } - $baselineWeight = (float)$classMetrics['methods'][$metrics->getMethod()][$method]; - if ($baselineWeight === $weight) { - return $row; - } - - if ($baselineWeight > $weight) { - $row[$key] .= PHP_EOL . 'Δ -' . round($baselineWeight - $weight, 3) . ''; - } - - if ($baselineWeight < $weight) { - $row[$key] .= PHP_EOL . 'Δ +' . round($weight - $baselineWeight, 3) . ''; - } + $row[$key] .= PHP_EOL . 'Δ ' . $delta->getValue() . ''; } return $row; diff --git a/src/Config/ConfigService.php b/src/Config/ConfigService.php index 9d831fe..221bb9f 100644 --- a/src/Config/ConfigService.php +++ b/src/Config/ConfigService.php @@ -16,14 +16,11 @@ class ConfigService * @var array */ private array $config; - private readonly Processor $processor; - private readonly ConfigLoader $configuration; - - public function __construct() - { - $this->processor = new Processor(); - $this->configuration = new ConfigLoader(); + public function __construct( + private readonly Processor $processor, + private readonly ConfigLoader $configuration + ) { $this->config = $this->processor->processConfiguration($this->configuration, [ Yaml::parseFile(__DIR__ . '/../../config.yml'), ]); diff --git a/src/PhpParser/CognitiveMetricsVisitor.php b/src/PhpParser/CognitiveMetricsVisitor.php index ed12532..02aadd7 100644 --- a/src/PhpParser/CognitiveMetricsVisitor.php +++ b/src/PhpParser/CognitiveMetricsVisitor.php @@ -97,14 +97,14 @@ private function initializeMethodContext(Node\Stmt\ClassMethod $node): void private function recordMethodMetrics(Node\Stmt\ClassMethod $node): void { $this->methodMetrics["{$this->currentClassName}::{$this->currentMethod}"] = [ - 'line_count' => $this->calculateLineCount($node), - 'arg_count' => $this->countMethodArguments($node), - 'return_count' => 0, - 'variable_count' => 0, - 'property_call_count' => 0, - 'if_nesting_level' => 0, - 'else_count' => 0, - 'if_count' => 0, + 'lineCount' => $this->calculateLineCount($node), + 'argCount' => $this->countMethodArguments($node), + 'returnCount' => 0, + 'variableCount' => 0, + 'propertyCallCount' => 0, + 'ifNestingLevel' => 0, + 'elseCount' => 0, + 'ifCount' => 0, ]; } @@ -258,14 +258,14 @@ private function writeMetricsOnLeaveNode(Node $node): void { if ($node instanceof Node\Stmt\ClassMethod) { $method = "{$this->currentClassName}::{$this->currentMethod}"; - $this->methodMetrics[$method]['return_count'] = $this->currentReturnCount; - $this->methodMetrics[$method]['variable_count'] = count($this->currentVariables); - $this->methodMetrics[$method]['property_call_count'] = $this->propertyCalls; - $this->methodMetrics[$method]['if_count'] = $this->ifCount; - $this->methodMetrics[$method]['if_nesting_level'] = $this->maxIfNestingLevel; - $this->methodMetrics[$method]['else_count'] = $this->elseCount; - $this->methodMetrics[$method]['line_count'] = $node->getEndLine() - $node->getStartLine() + 1; - $this->methodMetrics[$method]['arg_count'] = count($node->getParams()); + $this->methodMetrics[$method]['returnCount'] = $this->currentReturnCount; + $this->methodMetrics[$method]['variableCount'] = count($this->currentVariables); + $this->methodMetrics[$method]['propertyCallCount'] = $this->propertyCalls; + $this->methodMetrics[$method]['ifCount'] = $this->ifCount; + $this->methodMetrics[$method]['ifNestingLevel'] = $this->maxIfNestingLevel; + $this->methodMetrics[$method]['elseCount'] = $this->elseCount; + $this->methodMetrics[$method]['lineCount'] = $node->getEndLine() - $node->getStartLine() + 1; + $this->methodMetrics[$method]['argCount'] = count($node->getParams()); $this->currentMethod = ''; } } diff --git a/tests/TestCode2/TestClassForCounts.php b/tests/TestCode2/TestClassForCounts.php new file mode 100644 index 0000000..52648ac --- /dev/null +++ b/tests/TestCode2/TestClassForCounts.php @@ -0,0 +1,39 @@ + 0) { + $this->property = 'foo'; + $this->property2 = 'bar'; + } else { + return 'foo'; + } + + if (2 === 3) { + if ('this' !== 'that') { + return 'this'; + } + } + + return ''; + } +} diff --git a/tests/Unit/Business/Cognitive/CognitiveMetricsCollectorTest.php b/tests/Unit/Business/Cognitive/CognitiveMetricsCollectorTest.php index 7c41c4b..a57e9bf 100644 --- a/tests/Unit/Business/Cognitive/CognitiveMetricsCollectorTest.php +++ b/tests/Unit/Business/Cognitive/CognitiveMetricsCollectorTest.php @@ -7,6 +7,9 @@ use Phauthentic\CodeQualityMetrics\Business\AbstractMetricCollector; use Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetricsCollection; use Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetricsCollector; +use Phauthentic\CodeQualityMetrics\Business\DirectoryScanner; +use PhpParser\NodeTraverser; +use PhpParser\ParserFactory; use PHPUnit\Framework\TestCase; use RuntimeException; @@ -20,7 +23,11 @@ class CognitiveMetricsCollectorTest extends TestCase protected function setUp(): void { parent::setUp(); - $this->metricsCollector = new CognitiveMetricsCollector(); + $this->metricsCollector = new CognitiveMetricsCollector( + new ParserFactory(), + new NodeTraverser(), + new DirectoryScanner() + ); } public function testCollectWithValidDirectoryPath(): void @@ -56,4 +63,22 @@ public function testCollectWithUnreadableFile(): void $this->expectException(RuntimeException::class); $this->metricsCollector->collect($path); } + + /** + * Test the collected metrics to match the expected findings. + */ + public function testCollectedMetrics(): void + { + $metricsCollection = $this->metricsCollector->collect('./tests/TestCode2'); + $metrics = $metricsCollection->getClassWithMethod('\TestClassForCounts', 'test'); + + $this->assertNotNull($metrics); + $this->assertSame(5, $metrics->getArgCount()); + $this->assertSame(3, $metrics->getIfCount()); + $this->assertSame(2, $metrics->getIfNestingLevel()); + $this->assertSame(3, $metrics->getReturnCount()); + $this->assertSame(1, $metrics->getElseCount()); + $this->assertSame(3, $metrics->getVariableCount()); + $this->assertSame(2, $metrics->getPropertyCallCount()); + } } diff --git a/tests/Unit/Business/Cognitive/CognitiveMetricsTest.php b/tests/Unit/Business/Cognitive/CognitiveMetricsTest.php index fe12fef..e854d0d 100644 --- a/tests/Unit/Business/Cognitive/CognitiveMetricsTest.php +++ b/tests/Unit/Business/Cognitive/CognitiveMetricsTest.php @@ -5,6 +5,7 @@ namespace Phauthentic\CodeQualityMetrics\Tests\Unit\Business\Cognitive; use Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetrics; +use Phauthentic\CodeQualityMetrics\Business\Cognitive\Delta; use PHPUnit\Framework\TestCase; /** @@ -21,20 +22,20 @@ protected function setUp(): void $this->testMetricsData = [ 'class' => 'TestClass', 'method' => 'testMethod', - 'line_count' => 10, - 'arg_count' => 2, - 'return_count' => 1, - 'variable_count' => 5, - 'property_call_count' => 3, - 'if_count' => 4, - 'if_nesting_level' => 2, - 'else_count' => 1, + 'lineCount' => 10, + 'argCount' => 2, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, ]; } public function testConstructor(): void { - $metrics = new \Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetrics($this->testMetricsData); + $metrics = new CognitiveMetrics($this->testMetricsData); $this->assertSame('TestClass', $metrics->getClass()); $this->assertSame('testMethod', $metrics->getMethod()); @@ -82,27 +83,35 @@ public function testFromArray(): void public function testToArray(): void { - $metrics = new \Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetrics($this->testMetricsData); + $metrics = new CognitiveMetrics($this->testMetricsData); $expectedArray = [ 'class' => 'TestClass', 'method' => 'testMethod', - 'line_count' => 10, - 'arg_count' => 2, - 'return_count' => 1, - 'variable_count' => 5, - 'property_call_count' => 3, - 'if_count' => 4, - 'if_nesting_level' => 2, - 'else_count' => 1, - 'line_count_weight' => 0.0, - 'arg_count_weight' => 0.0, - 'return_count_weight' => 0.0, - 'variable_count_weight' => 0.0, - 'property_call_count_weight' => 0.0, - 'if_count_weight' => 0.0, - 'if_nesting_level_weight' => 0.0, - 'else_count_weight' => 0.0, + 'lineCount' => 10, + 'argCount' => 2, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, + 'lineCountWeight' => 0.0, + 'argCountWeight' => 0.0, + 'returnCountWeight' => 0.0, + 'variableCountWeight' => 0.0, + 'propertyCallCountWeight' => 0.0, + 'ifCountWeight' => 0.0, + 'ifNestingLevelWeight' => 0.0, + 'elseCountWeight' => 0.0, + 'lineCountWeightDelta' => null, + 'argCountWeightDelta' => null, + 'returnCountWeightDelta' => null, + 'variableCountWeightDelta' => null, + 'propertyCallCountWeightDelta' => null, + 'ifCountWeightDelta' => null, + 'ifNestingLevelWeightDelta' => null, + 'elseCountWeightDelta' => null, ]; $this->assertSame($expectedArray, $metrics->toArray()); @@ -110,29 +119,116 @@ public function testToArray(): void public function testJsonSerialize(): void { - $metrics = new \Phauthentic\CodeQualityMetrics\Business\Cognitive\CognitiveMetrics($this->testMetricsData); + $metrics = new CognitiveMetrics($this->testMetricsData); $expectedArray = [ 'class' => 'TestClass', 'method' => 'testMethod', - 'line_count' => 10, - 'arg_count' => 2, - 'return_count' => 1, - 'variable_count' => 5, - 'property_call_count' => 3, - 'if_count' => 4, - 'if_nesting_level' => 2, - 'else_count' => 1, - 'line_count_weight' => 0.0, - 'arg_count_weight' => 0.0, - 'return_count_weight' => 0.0, - 'variable_count_weight' => 0.0, - 'property_call_count_weight' => 0.0, - 'if_count_weight' => 0.0, - 'if_nesting_level_weight' => 0.0, - 'else_count_weight' => 0.0, + 'lineCount' => 10, + 'argCount' => 2, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, + 'lineCountWeight' => 0.0, + 'argCountWeight' => 0.0, + 'returnCountWeight' => 0.0, + 'variableCountWeight' => 0.0, + 'propertyCallCountWeight' => 0.0, + 'ifCountWeight' => 0.0, + 'ifNestingLevelWeight' => 0.0, + 'elseCountWeight' => 0.0, + 'lineCountWeightDelta' => null, + 'argCountWeightDelta' => null, + 'returnCountWeightDelta' => null, + 'variableCountWeightDelta' => null, + 'propertyCallCountWeightDelta' => null, + 'ifCountWeightDelta' => null, + 'ifNestingLevelWeightDelta' => null, + 'elseCountWeightDelta' => null, ]; $this->assertSame($expectedArray, $metrics->jsonSerialize()); } + + public function testCalculateDeltas(): void + { + // Create first set of metrics + $presentMetrics = new CognitiveMetrics([ + 'class' => 'TestClass', + 'method' => 'testMethod', + 'lineCount' => 10, + 'argCount' => 2, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, + ]); + + // Set weights for metrics1 + $presentMetrics->setLineCountWeight(1.5); + $presentMetrics->setArgCountWeight(0.5); + $presentMetrics->setReturnCountWeight(2.0); + $presentMetrics->setVariableCountWeight(1.0); + $presentMetrics->setPropertyCallCountWeight(1.5); + $presentMetrics->setIfCountWeight(0.0); + $presentMetrics->setIfNestingLevelWeight(1.0); + $presentMetrics->setElseCountWeight(0.5); + + // Create second set of metrics with different weights + $beforeMetrics = new CognitiveMetrics([ + 'class' => 'TestClass', + 'method' => 'testMethod', + 'lineCount' => 10, + 'argCount' => 2, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, + ]); + + // Set weights for metrics2 + $beforeMetrics->setLineCountWeight(1.0); + $beforeMetrics->setArgCountWeight(1.0); + $beforeMetrics->setReturnCountWeight(2.5); + $beforeMetrics->setVariableCountWeight(1.0); + $beforeMetrics->setPropertyCallCountWeight(2.0); + $beforeMetrics->setIfCountWeight(0.0); + $beforeMetrics->setIfNestingLevelWeight(2.0); + $beforeMetrics->setElseCountWeight(0.5); + + // Calculate deltas + $presentMetrics->calculateDeltas($beforeMetrics); + + // Check deltas for each weight + $this->assertInstanceOf(Delta::class, $presentMetrics->getLineCountWeightDelta()); + $this->assertEquals(0.5, $presentMetrics->getLineCountWeightDelta()->getValue()); + + $this->assertInstanceOf(Delta::class, $presentMetrics->getArgCountWeightDelta()); + $this->assertEquals(-0.5, $presentMetrics->getArgCountWeightDelta()->getValue()); + + $this->assertInstanceOf(Delta::class, $presentMetrics->getReturnCountWeightDelta()); + $this->assertEquals(-0.5, $presentMetrics->getReturnCountWeightDelta()->getValue()); + + $this->assertInstanceOf(Delta::class, $presentMetrics->getVariableCountWeightDelta()); + $this->assertEquals(0.0, $presentMetrics->getVariableCountWeightDelta()->getValue()); + + $this->assertInstanceOf(Delta::class, $presentMetrics->getPropertyCallCountWeightDelta()); + $this->assertEquals(-0.5, $presentMetrics->getPropertyCallCountWeightDelta()->getValue()); + + $this->assertInstanceOf(Delta::class, $presentMetrics->getIfCountWeightDelta()); + $this->assertEquals(0.0, $presentMetrics->getIfCountWeightDelta()->getValue()); + + $this->assertInstanceOf(Delta::class, $presentMetrics->getIfNestingLevelWeightDelta()); + $this->assertEquals(-1.0, $presentMetrics->getIfNestingLevelWeightDelta()->getValue()); + + $this->assertInstanceOf(Delta::class, $presentMetrics->getElseCountWeightDelta()); + $this->assertEquals(0.0, $presentMetrics->getElseCountWeightDelta()->getValue()); + } } diff --git a/tests/Unit/Business/Cognitive/DeltaTest.php b/tests/Unit/Business/Cognitive/DeltaTest.php new file mode 100644 index 0000000..2591797 --- /dev/null +++ b/tests/Unit/Business/Cognitive/DeltaTest.php @@ -0,0 +1,47 @@ +assertTrue($delta->hasIncreased()); + $this->assertSame(5.0, $delta->getValue()); + } + + public function testDeltaWhenDecreased(): void + { + $before = 10.0; + $after = 5.0; + + $delta = new Delta($before, $after); + + $this->assertFalse($delta->hasIncreased()); + $this->assertSame(-5.0, $delta->getValue()); + } + + public function testDeltaWhenEqual(): void + { + $before = 10.0; + $after = 10.0; + + $delta = new Delta($before, $after); + + $this->assertFalse($delta->hasIncreased()); + $this->assertSame(0.0, $delta->getValue()); + } +} diff --git a/tests/Unit/Business/Cognitive/Exporter/CsvExporterTest.php b/tests/Unit/Business/Cognitive/Exporter/CsvExporterTest.php index dc22b7f..a54794a 100644 --- a/tests/Unit/Business/Cognitive/Exporter/CsvExporterTest.php +++ b/tests/Unit/Business/Cognitive/Exporter/CsvExporterTest.php @@ -39,23 +39,24 @@ public function testExportCreatesFile(): void $metrics = new CognitiveMetrics([ 'class' => 'TestClass', 'method' => 'testMethod', - 'line_count' => 10, - 'arg_count' => 2, - 'return_count' => 1, - 'variable_count' => 5, - 'property_call_count' => 3, - 'if_count' => 4, - 'if_nesting_level' => 2, - 'else_count' => 1, - 'line_count_weight' => 0.5, - 'arg_count_weight' => 0.3, - 'return_count_weight' => 0.2, - 'variable_count_weight' => 0.4, - 'property_call_count_weight' => 0.3, - 'if_count_weight' => 0.6, - 'if_nesting_level_weight' => 0.5, - 'else_count_weight' => 0.2, + 'lineCount' => 10, + 'argCount' => 2, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, + 'lineCountWeight' => 0.5, + 'argCountWeight' => 0.3, + 'returnCountWeight' => 0.2, + 'variableCountWeight' => 0.4, + 'propertyCallCountWeight' => 0.3, + 'ifCountWeight' => 0.6, + 'ifNestingLevelWeight' => 0.5, + 'elseCountWeight' => 0.2, ]); + $metricsCollection->add($metrics); $this->csvExporter->export($metricsCollection, $this->filename); diff --git a/tests/Unit/Business/Cognitive/Exporter/JsonExporterTest.php b/tests/Unit/Business/Cognitive/Exporter/JsonExporterTest.php index 88999cb..98582af 100644 --- a/tests/Unit/Business/Cognitive/Exporter/JsonExporterTest.php +++ b/tests/Unit/Business/Cognitive/Exporter/JsonExporterTest.php @@ -28,26 +28,27 @@ public function testExport(): void $metrics1 = new CognitiveMetrics([ 'class' => 'TestClass1', 'method' => 'testMethod1', - 'line_count' => 10, - 'arg_count' => 2, - 'return_count' => 1, - 'variable_count' => 5, - 'property_call_count' => 3, - 'if_count' => 4, - 'if_nesting_level' => 2, - 'else_count' => 1, + 'lineCount' => 10, + 'argCount' => 2, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, ]); + $metrics2 = new CognitiveMetrics([ 'class' => 'TestClass2', 'method' => 'testMethod2', - 'line_count' => 15, - 'arg_count' => 3, - 'return_count' => 1, - 'variable_count' => 5, - 'property_call_count' => 3, - 'if_count' => 4, - 'if_nesting_level' => 2, - 'else_count' => 1, + 'lineCount' => 15, + 'argCount' => 3, + 'returnCount' => 1, + 'variableCount' => 5, + 'propertyCallCount' => 3, + 'ifCount' => 4, + 'ifNestingLevel' => 2, + 'elseCount' => 1, ]); $metricsCollection->add($metrics1); @@ -62,11 +63,11 @@ public function testExport(): void $decodedData = json_decode($jsonData, true); $expected = [ - [ - 'class' => 'TestClass1', + 'TestClass1' => [ 'methods' => [ 'testMethod1' => [ - 'name' => 'testMethod1', + 'class' => 'TestClass1', + 'method' => 'testMethod1', 'lineCount' => 10, 'lineCountWeight' => 0, 'argCount' => 2, @@ -83,15 +84,15 @@ public function testExport(): void 'ifNestingLevelWeight' => 0, 'elseCount' => 1, 'elseCountWeight' => 0, - 'score' => 0 + 'score' => 0, ] ] - ], - [ - 'class' => 'TestClass2', + ], + 'TestClass2' => [ 'methods' => [ 'testMethod2' => [ - 'name' => 'testMethod2', + 'class' => 'TestClass2', + 'method' => 'testMethod2', 'lineCount' => 15, 'lineCountWeight' => 0, 'argCount' => 3, @@ -108,10 +109,10 @@ public function testExport(): void 'ifNestingLevelWeight' => 0, 'elseCount' => 1, 'elseCountWeight' => 0, - 'score' => 0 + 'score' => 0, ] ] - ] + ] ]; $this->assertSame($expected, $decodedData); diff --git a/tests/Unit/Business/Cognitive/ScoreCalculatorTest.php b/tests/Unit/Business/Cognitive/ScoreCalculatorTest.php index db9a2d9..0a4d092 100644 --- a/tests/Unit/Business/Cognitive/ScoreCalculatorTest.php +++ b/tests/Unit/Business/Cognitive/ScoreCalculatorTest.php @@ -25,20 +25,23 @@ protected function setUp(): void $this->metrics = new CognitiveMetrics([ 'class' => 'Test', 'method' => 'test', - 'line_count' => 10, - 'arg_count' => 5, - 'return_count' => 2, - 'variable_count' => 3, - 'property_call_count' => 2, - 'if_count' => 3, - 'if_nesting_level' => 2, - 'else_count' => 2, + 'lineCount' => 10, + 'argCount' => 5, + 'returnCount' => 2, + 'variableCount' => 3, + 'propertyCallCount' => 2, + 'ifCount' => 3, + 'ifNestingLevel' => 2, + 'elseCount' => 2, ]); } public function testCalculate(): void { - $config = (new ConfigService())->getConfig(); + $config = (new ConfigService( + new Processor(), + new ConfigLoader() + ))->getConfig(); $this->scoreCalculator->calculate($this->metrics, $config['cognitive']); diff --git a/tests/Unit/Business/Halstead/HalsteadMetricsCollectorTest.php b/tests/Unit/Business/Halstead/HalsteadMetricsCollectorTest.php index 40c0304..0d13455 100644 --- a/tests/Unit/Business/Halstead/HalsteadMetricsCollectorTest.php +++ b/tests/Unit/Business/Halstead/HalsteadMetricsCollectorTest.php @@ -4,7 +4,10 @@ namespace Phauthentic\CodeQualityMetrics\Tests\Unit\Business\Halstead; +use Phauthentic\CodeQualityMetrics\Business\DirectoryScanner; use Phauthentic\CodeQualityMetrics\Business\Halstead\HalsteadMetricsCollector; +use PhpParser\NodeTraverser; +use PhpParser\ParserFactory; use PHPUnit\Framework\TestCase; /** @@ -14,7 +17,11 @@ class HalsteadMetricsCollectorTest extends TestCase { public function testCount() { - $collector = new HalsteadMetricsCollector(); + $collector = new HalsteadMetricsCollector( + new ParserFactory(), + new NodeTraverser(), + new DirectoryScanner() + ); $collection = $collector->collect('./tests/TestCode'); $this->assertCount(4, $collection); diff --git a/tests/Unit/Business/MetricsFacadeTest.php b/tests/Unit/Business/MetricsFacadeTest.php index a3bb75f..79e0b50 100644 --- a/tests/Unit/Business/MetricsFacadeTest.php +++ b/tests/Unit/Business/MetricsFacadeTest.php @@ -4,6 +4,11 @@ namespace Phauthentic\CodeQualityMetrics\Tests\Unit\Business; +use Phauthentic\CodeQualityMetrics\Application; +use Phauthentic\CodeQualityMetrics\Business\Cognitive\ScoreCalculator; +use Phauthentic\CodeQualityMetrics\Business\Halstead\HalsteadMetricsCollector; +use Phauthentic\CodeQualityMetrics\Config\ConfigService; +use PHP_CodeSniffer\Config; use PHPUnit\Framework\TestCase; use Phauthentic\CodeQualityMetrics\Business\MetricsFacade; use Symfony\Component\Yaml\Exception\ParseException; @@ -13,13 +18,19 @@ */ class MetricsFacadeTest extends TestCase { - private $testCodePath = './tests/TestCode'; + private string $testCodePath = './tests/TestCode'; - public function testGetHalsteadMetrics(): void + private MetricsFacade $metricsFacade; + + public function setUp(): void { - $facade = new MetricsFacade(); + parent::setUp(); + $this->metricsFacade = (new Application())->get(MetricsFacade::class); + } - $halsteadMetrics = $facade->getHalsteadMetrics($this->testCodePath); + public function testGetHalsteadMetrics(): void + { + $halsteadMetrics = $this->metricsFacade->getHalsteadMetrics($this->testCodePath); $this->assertNotEmpty($halsteadMetrics); $this->assertCount(4, $halsteadMetrics); @@ -27,9 +38,7 @@ public function testGetHalsteadMetrics(): void public function testGetCognitiveMetrics(): void { - $facade = new MetricsFacade(); - - $cognitiveMetrics = $facade->getCognitiveMetrics($this->testCodePath); + $cognitiveMetrics = $this->metricsFacade->getCognitiveMetrics($this->testCodePath); $this->assertNotEmpty($cognitiveMetrics); $this->assertCount(23, $cognitiveMetrics); @@ -37,10 +46,8 @@ public function testGetCognitiveMetrics(): void public function testLoadConfig(): void { - $facade = new MetricsFacade(); - // Load a valid configuration file - $facade->loadConfig('./tests/Fixtures/config-with-one-metric.yml'); + $this->metricsFacade->loadConfig('./tests/Fixtures/config-with-one-metric.yml'); // Assuming the loadConfig method in ConfigService is correctly tested, // here we're just ensuring that it doesn't throw exceptions @@ -49,10 +56,8 @@ public function testLoadConfig(): void public function testLoadConfigWithInvalidConfigFile(): void { - $facade = new MetricsFacade(); - $this->expectException(ParseException::class); - $facade->loadConfig('./does-not-exist.yml'); + $this->metricsFacade->loadConfig('./does-not-exist.yml'); } } diff --git a/tests/Unit/PhpParser/CognitiveMetricsVisitorTest.php b/tests/Unit/PhpParser/CognitiveMetricsVisitorTest.php index 0ae0cce..2d7c311 100644 --- a/tests/Unit/PhpParser/CognitiveMetricsVisitorTest.php +++ b/tests/Unit/PhpParser/CognitiveMetricsVisitorTest.php @@ -55,13 +55,13 @@ public function testMethodMetricsCalculation(): void $this->assertArrayHasKey('MyNamespace\\MyClass::myMethod', $methodMetrics); $metrics = $methodMetrics['MyNamespace\\MyClass::myMethod']; - $this->assertEquals(12, $metrics['line_count']); - $this->assertEquals(2, $metrics['arg_count']); - $this->assertEquals(3, $metrics['return_count']); - $this->assertEquals(2, $metrics['variable_count']); - $this->assertEquals(0, $metrics['property_call_count']); - $this->assertEquals(1, $metrics['if_count']); - $this->assertEquals(1, $metrics['if_nesting_level']); - $this->assertEquals(2, $metrics['else_count']); + $this->assertEquals(12, $metrics['lineCount']); + $this->assertEquals(2, $metrics['argCount']); + $this->assertEquals(3, $metrics['returnCount']); + $this->assertEquals(2, $metrics['variableCount']); + $this->assertEquals(0, $metrics['propertyCallCount']); + $this->assertEquals(1, $metrics['ifCount']); + $this->assertEquals(1, $metrics['ifNestingLevel']); + $this->assertEquals(2, $metrics['elseCount']); } }