diff --git a/.gitignore b/.gitignore index 35e5201248d868867722de48807731d5d4125481..6b8acbf7850bb0c5915e0ff57f782ffa08df1eab 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ /phpunit.xml /phpstan.neon /.php-cs-fixer.php + +/resources/tools diff --git a/.gitlab/ci/analysis/php-cs-fixer.yml b/.gitlab/ci/analysis/php-cs-fixer.yml index cafcdf2f021302e2b7febc4bae10576542ca9bb0..9abff904d115160af501ebfb0146af06778f0755 100644 --- a/.gitlab/ci/analysis/php-cs-fixer.yml +++ b/.gitlab/ci/analysis/php-cs-fixer.yml @@ -12,15 +12,13 @@ php-cs-fixer: allow_failure: false dependencies: - composer - - phive cache: {} needs: - composer - - phive interruptible: true script: - | - ./resources/tools/php-cs-fixer fix \ + ./vendor/bin/php-cs-fixer fix \ --config=./.php-cs-fixer.dist.php \ --format=gitlab \ --verbose \ diff --git a/.gitlab/ci/analysis/phpcpd.yml b/.gitlab/ci/analysis/phpcpd.yml deleted file mode 100644 index 30f4c023f799fa4731c7dae344ef2f3c09d01c61..0000000000000000000000000000000000000000 --- a/.gitlab/ci/analysis/phpcpd.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- - -phpcpd: - stage: analysis - image: php:cli-alpine - rules: - - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - when: on_success - allow_failure: false - - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - when: on_success - allow_failure: false - dependencies: - - phive - cache: {} - needs: - - phive - interruptible: true - script: - - | - ./resources/tools/phpcpd \ - --min-lines=20 \ - --fuzzy \ - --suffix .php \ - --suffix .module \ - --suffix .install \ - --suffix .theme \ - --suffix .inc \ - ./src diff --git a/.gitlab/ci/analysis/phpstan.yml b/.gitlab/ci/analysis/phpstan.yml index 4f289a3a3860ce45bc4e41b829a13b127b044ccf..3d95a6e334ab3127061302d23cef756677690744 100644 --- a/.gitlab/ci/analysis/phpstan.yml +++ b/.gitlab/ci/analysis/phpstan.yml @@ -12,15 +12,13 @@ phpstan: allow_failure: false dependencies: - composer - - phive cache: {} needs: - composer - - phive interruptible: true script: - | - ./resources/tools/phpstan analyse \ + ./vendor/bin/phpstan analyse \ --no-progress \ --memory-limit=-1 \ --error-format=gitlab \ diff --git a/.gitlab/ci/build/phive.yml b/.gitlab/ci/build/phive.yml deleted file mode 100644 index 9b6ab23b19a5552164d00ea276a403fa71fa0d1b..0000000000000000000000000000000000000000 --- a/.gitlab/ci/build/phive.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- - -phive: - stage: build - image: php:cli-alpine - rules: - - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - when: on_success - allow_failure: false - - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - when: on_success - allow_failure: false - dependencies: [] - cache: - key: 'phive-cache' - when: always - policy: pull-push - paths: - - ./.phive-cache - needs: [] - interruptible: true - variables: - PHIVE_HOME: ./.phive-cache - before_script: - - apk add --no-cache gnupg - - curl -sSL "https://phar.io/releases/phive.phar" -o ./phive.phar - - chmod +x ./phive.phar - script: - - ./phive.phar install --trust-gpg-keys E82B2FB314E9906E,51C67305FFC2E5C0,4AA394086372C20A - artifacts: - expire_in: 1 day - paths: - - ./resources/tools diff --git a/.gitlab/ci/test/phpunit.yml b/.gitlab/ci/test/phpunit.yml index 55ae55d2f32a1fb5e4d60440dda09d5806fcfb52..bd1289efbbfd95d7c1c461631b2ddfaed9764e22 100644 --- a/.gitlab/ci/test/phpunit.yml +++ b/.gitlab/ci/test/phpunit.yml @@ -12,11 +12,9 @@ phpunit: allow_failure: false dependencies: - composer - - phive cache: {} needs: - composer - - phive interruptible: true variables: XDEBUG_MODE: coverage @@ -26,7 +24,7 @@ phpunit: - echo "extension=pcov.so" > $PHP_INI_DIR/conf.d/pcov.ini script: - | - ./resources/tools/phpunit \ + ./vendor/bin/phpunit \ --do-not-cache-result \ --coverage-text \ --coverage-cobertura cobertura.phpunit.xml \ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index df93505733e1413e9ac186c4ac50e4fe9900ace8..fc99f0605efdc4cae2c16d263235c0b20c27ddc4 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -9,11 +9,16 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ +use Composer\InstalledVersions; +use PhpCsFixer\Config; +use PhpCsFixer\Finder; +use XpertSelect\Tools\ProjectType; + // This file was generated using XpertSelect/Tools. Please refer to the README for more information. include 'vendor/autoload.php'; -$package = Composer\InstalledVersions::getRootPackage()['name']; -$rules = include XpertSelect\Tools\ProjectType::Standard->phpCsFixerRuleFile(); +$package = InstalledVersions::getRootPackage()['name']; +$rules = include ProjectType::Standard->phpCsFixerRuleFile(); $rules['header_comment']['header'] = trim(' This file is part of the ' . $package . ' package. @@ -22,13 +27,12 @@ This source file is subject to the license that is bundled with this source code in the LICENSE.md file. '); -$finder = PhpCsFixer\Finder::create() +$finder = Finder::create() ->in([__DIR__]) - ->append([__DIR__ . '/bin/xs-config', __DIR__ . '/bin/xs-dependencies']) ->ignoreDotFiles(false) ->ignoreVCSIgnored(true); -return (new PhpCsFixer\Config('XpertSelect/PHP')) +return (new Config('XpertSelect/PHP')) ->setIndent(' ') ->setLineEnding("\n") ->setRules($rules) diff --git a/bin/xs-config b/bin/xs-config deleted file mode 100755 index 620c7bcf1701bce179e7ed6519e80277728209ce..0000000000000000000000000000000000000000 --- a/bin/xs-config +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env php -publishFiles() - ->generateGitIgnoreFiles(); diff --git a/bin/xs-dependencies b/bin/xs-dependencies deleted file mode 100755 index a8f0809dbf46360b29f9c36e22123ed5c96b6c52..0000000000000000000000000000000000000000 --- a/bin/xs-dependencies +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env php -=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.6.2", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + }, + "time": "2025-10-21T19:32:17+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "php-cs-fixer/shim", + "version": "v3.89.2", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/shim.git", + "reference": "8f1bf4fd7d8270020cd3c58756fcf3615ed14b68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/8f1bf4fd7d8270020cd3c58756fcf3615ed14b68", + "reference": "8f1bf4fd7d8270020cd3c58756fcf3615ed14b68", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "replace": { + "friendsofphp/php-cs-fixer": "self.version" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer", + "php-cs-fixer.phar" + ], + "type": "application", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/PHP-CS-Fixer/shim/issues", + "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.89.2" + }, + "time": "2025-11-06T21:13:10+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.31", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96", + "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-10-10T14:14:11+00:00" + }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "2.0.7", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/d6211c46213d4181054b3d77b10a5c5cb0d59538", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.29" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.7" + }, + "time": "2025-09-26T11:19:08+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", + "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "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.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.2" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "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.11" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-08-27T14:37:49+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "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.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-27T05:02:59+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.43", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "c6b89b6cf4324a8b4cb86e1f5dfdd6c9e0371924" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c6b89b6cf4324a8b4cb86e1f5dfdd6c9e0371924", + "reference": "c6b89b6cf4324a8b4cb86e1f5dfdd6c9e0371924", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.11", + "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.3", + "sebastian/comparator": "^6.3.2", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.43" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-10-30T08:39:39+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "react/promise", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.12.28 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-08-19T18:57:03+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", + "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2025-08-10T08:07:46+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:12:51+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-13T04:42:22+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:55:48+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2024-07-11T14:55:45+00:00" + }, + { + "name": "seld/phar-utils", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "support": { + "issues": "https://github.com/Seldaek/phar-utils/issues", + "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1" + }, + "time": "2022-08-31T10:31:18+00:00" + }, + { + "name": "seld/signal-handler", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/signal-handler.git", + "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98", + "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "phpstan/phpstan": "^1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^7.5.20 || ^8.5.23", + "psr/log": "^1 || ^2 || ^3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\Signal\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development", + "keywords": [ + "posix", + "sigint", + "signal", + "sigterm", + "unix" + ], + "support": { + "issues": "https://github.com/Seldaek/signal-handler/issues", + "source": "https://github.com/Seldaek/signal-handler/tree/2.0.2" + }, + "time": "2023-09-03T09:24:00+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/console", + "version": "v7.3.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "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": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.3.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-11-04T01:21:42+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "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": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "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-25T14:21:43+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.3.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "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": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.3.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-11-05T09:52:27+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "9f696d2f1e340484b4683f7853b273abff94421f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f", + "reference": "9f696d2f1e340484b4683f7853b273abff94421f", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "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": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-10-15T18:45:57+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "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": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "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": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "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": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "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": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" }, { - "name": "hamcrest/hamcrest-php", - "version": "v2.1.1", + "name": "symfony/polyfill-php81", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", - "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": "^7.4|^8.0" + "php": ">=7.2" }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } }, - "require-dev": { - "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", - "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "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": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "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": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-09-11T10:12:26+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-master": "2.1-dev" + "dev-main": "3.6-dev" } }, "autoload": { - "classmap": [ - "hamcrest" + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "description": "This is the PHP port of Hamcrest Matchers", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", "keywords": [ - "test" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "issues": "https://github.com/hamcrest/hamcrest-php/issues", - "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, - "time": "2025-04-30T06:54:44+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T11:30:57+00:00" }, { - "name": "mockery/mockery", - "version": "1.6.12", + "name": "symfony/string", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + "url": "https://github.com/symfony/string.git", + "reference": "f96476035142921000338bad71e5247fbc138872" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", - "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", + "reference": "f96476035142921000338bad71e5247fbc138872", "shasum": "" }, "require": { - "hamcrest/hamcrest-php": "^2.0.1", - "lib-pcre": ">=7.0", - "php": ">=7.3" + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "phpunit/phpunit": "<8.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.6.17", - "symplify/easy-coding-standard": "^12.1.14" + "symfony/emoji": "^7.1", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" }, "type": "library", "autoload": { "files": [ - "library/helpers.php", - "library/Mockery.php" + "Resources/functions.php" ], "psr-4": { - "Mockery\\": "library/Mockery" - } + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "https://github.com/padraic", - "role": "Author" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "https://davedevelopment.co.uk", - "role": "Developer" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "name": "Nathanael Esayeas", - "email": "nathanael.esayeas@protonmail.com", - "homepage": "https://github.com/ghostwriter", - "role": "Lead Developer" + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "Mockery is a simple yet flexible PHP mock object framework", - "homepage": "https://github.com/mockery/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" + "time": "2025-09-11T14:36:48+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { - "docs": "https://docs.mockery.io/", - "issues": "https://github.com/mockery/mockery/issues", - "rss": "https://github.com/mockery/mockery/releases.atom", - "security": "https://github.com/mockery/mockery/security/advisories", - "source": "https://github.com/mockery/mockery" + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, - "time": "2024-05-16T03:13:13+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" } ], - "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.2", + "composer-plugin-api": "^2.0", "composer-runtime-api": "^2.2" }, - "platform-dev": {}, + "platform-dev": [], "plugin-api-version": "2.6.0" } diff --git a/phive.xml b/phive.xml deleted file mode 100644 index dd5925366f7637220ed06cd629a0bdd4bfe62d64..0000000000000000000000000000000000000000 --- a/phive.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 94b5465c9937e3655e6fad33d7db484447c33c46..603adbd80b2219b03b0283850ea912fe754b2ca1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,6 @@ diff --git a/resources/config/drupal-package/.php-cs-fixer.dist.php b/resources/config/Drupal/10.x/Module/.php-cs-fixer.dist.php similarity index 74% rename from resources/config/drupal-package/.php-cs-fixer.dist.php rename to resources/config/Drupal/10.x/Module/.php-cs-fixer.dist.php index b996a83b889d26eaddbb6f5d3e7dc9c1a05d50f2..8407711780b959901caccac16fecbad266069bd9 100644 --- a/resources/config/drupal-package/.php-cs-fixer.dist.php +++ b/resources/config/Drupal/10.x/Module/.php-cs-fixer.dist.php @@ -9,11 +9,16 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ +use Composer\InstalledVersions; +use PhpCsFixer\Config; +use PhpCsFixer\Finder; +use XpertSelect\Tools\ProjectType; + // This file was generated using XpertSelect/Tools. Please refer to the README for more information. include 'vendor/autoload.php'; -$package = Composer\InstalledVersions::getRootPackage()['name']; -$rules = include XpertSelect\Tools\ProjectType::DrupalPackage->phpCsFixerRuleFile(); +$package = InstalledVersions::getRootPackage()['name']; +$rules = include ProjectType::DrupalPackage->phpCsFixerRuleFile(); $rules['header_comment']['header'] = trim(' This file is part of the ' . $package . ' package. @@ -22,7 +27,7 @@ This source file is subject to the license that is bundled with this source code in the LICENSE.md file. '); -$finder = PhpCsFixer\Finder::create() +$finder = Finder::create() ->in([__DIR__]) ->name('*.inc') ->name('*.install') @@ -34,7 +39,7 @@ $finder = PhpCsFixer\Finder::create() ->ignoreDotFiles(false) ->ignoreVCSIgnored(true); -return (new PhpCsFixer\Config('XpertSelect/Drupal')) +return (new Config('XpertSelect/Drupal')) ->setIndent(' ') ->setLineEnding("\n") ->setRules($rules) diff --git a/resources/config/drupal-package/.yamllint.yml b/resources/config/Drupal/10.x/Module/.yamllint.yml similarity index 100% rename from resources/config/drupal-package/.yamllint.yml rename to resources/config/Drupal/10.x/Module/.yamllint.yml diff --git a/resources/config/drupal-package/phpstan.neon.dist b/resources/config/Drupal/10.x/Module/phpstan.neon.dist similarity index 100% rename from resources/config/drupal-package/phpstan.neon.dist rename to resources/config/Drupal/10.x/Module/phpstan.neon.dist diff --git a/resources/config/Drupal/10.x/Module/phpunit.xml.dist b/resources/config/Drupal/10.x/Module/phpunit.xml.dist new file mode 100644 index 0000000000000000000000000000000000000000..50e40b5f5525f34cb14a07a2b27fd2d455237473 --- /dev/null +++ b/resources/config/Drupal/10.x/Module/phpunit.xml.dist @@ -0,0 +1,34 @@ + + + + + src + + + vendor + + + + + + + + + + tests/Unit + + + + tests/Functional + + + + + + + + + diff --git a/resources/config/drupal-project/.php-cs-fixer.dist.php b/resources/config/Drupal/10.x/Project/.php-cs-fixer.dist.php similarity index 76% rename from resources/config/drupal-project/.php-cs-fixer.dist.php rename to resources/config/Drupal/10.x/Project/.php-cs-fixer.dist.php index cb5510a191f3842b86d05fc17338bfcd5658590d..d63a7c199eababc9560d90f5a434e70708307c83 100644 --- a/resources/config/drupal-project/.php-cs-fixer.dist.php +++ b/resources/config/Drupal/10.x/Project/.php-cs-fixer.dist.php @@ -9,11 +9,16 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ +use Composer\InstalledVersions; +use PhpCsFixer\Config; +use PhpCsFixer\Finder; +use XpertSelect\Tools\ProjectType; + // This file was generated using XpertSelect/Tools. Please refer to the README for more information. include 'vendor/autoload.php'; -$package = Composer\InstalledVersions::getRootPackage()['name']; -$rules = include XpertSelect\Tools\ProjectType::DrupalProject->phpCsFixerRuleFile(); +$package = InstalledVersions::getRootPackage()['name']; +$rules = include ProjectType::DrupalProject->phpCsFixerRuleFile(); $rules['header_comment']['header'] = trim(' This file is part of the ' . $package . ' project. @@ -22,7 +27,7 @@ This source file is subject to the license that is bundled with this source code in the LICENSE.md file. '); -$finder = PhpCsFixer\Finder::create() +$finder = Finder::create() ->in([ __DIR__ . '/web/modules/custom', __DIR__ . '/web/profiles/custom', @@ -38,7 +43,7 @@ $finder = PhpCsFixer\Finder::create() ->ignoreDotFiles(false) ->ignoreVCSIgnored(true); -return (new PhpCsFixer\Config('XpertSelect/Drupal')) +return (new Config('XpertSelect/Drupal')) ->setIndent(' ') ->setLineEnding("\n") ->setRules($rules) diff --git a/resources/config/drupal-project/.yamllint.yml b/resources/config/Drupal/10.x/Project/.yamllint.yml similarity index 100% rename from resources/config/drupal-project/.yamllint.yml rename to resources/config/Drupal/10.x/Project/.yamllint.yml diff --git a/resources/config/drupal-project/phpstan.neon.dist b/resources/config/Drupal/10.x/Project/phpstan.neon.dist similarity index 100% rename from resources/config/drupal-project/phpstan.neon.dist rename to resources/config/Drupal/10.x/Project/phpstan.neon.dist diff --git a/resources/config/Drupal/10.x/Project/phpunit.xml.dist b/resources/config/Drupal/10.x/Project/phpunit.xml.dist new file mode 100644 index 0000000000000000000000000000000000000000..9222a23effa59e0627e3031d8350c5117ac1c017 --- /dev/null +++ b/resources/config/Drupal/10.x/Project/phpunit.xml.dist @@ -0,0 +1,36 @@ + + + + + web/modules/custom + web/profiles/custom + web/themes/custom + + + vendor + + + + + + + + + + tests/Unit + + + + tests/Functional + + + + + + + + + diff --git a/resources/config/Drupal/11.x/Module/.php-cs-fixer.dist.php b/resources/config/Drupal/11.x/Module/.php-cs-fixer.dist.php new file mode 100644 index 0000000000000000000000000000000000000000..8407711780b959901caccac16fecbad266069bd9 --- /dev/null +++ b/resources/config/Drupal/11.x/Module/.php-cs-fixer.dist.php @@ -0,0 +1,46 @@ +phpCsFixerRuleFile(); + +$rules['header_comment']['header'] = trim(' +This file is part of the ' . $package . ' package. + +This source file is subject to the license that is +bundled with this source code in the LICENSE.md file. +'); + +$finder = Finder::create() + ->in([__DIR__]) + ->name('*.inc') + ->name('*.install') + ->name('*.module') + ->name('*.profile') + ->name('*.php') + ->name('*.theme') + ->append([__FILE__]) + ->ignoreDotFiles(false) + ->ignoreVCSIgnored(true); + +return (new Config('XpertSelect/Drupal')) + ->setIndent(' ') + ->setLineEnding("\n") + ->setRules($rules) + ->setFinder($finder); diff --git a/resources/config/laravel-package/.yamllint.yml b/resources/config/Drupal/11.x/Module/.yamllint.yml similarity index 100% rename from resources/config/laravel-package/.yamllint.yml rename to resources/config/Drupal/11.x/Module/.yamllint.yml diff --git a/resources/config/Drupal/11.x/Module/phpstan.neon.dist b/resources/config/Drupal/11.x/Module/phpstan.neon.dist new file mode 100644 index 0000000000000000000000000000000000000000..5b6c90ebacd630d11c68d4ef882b25c5d50cfe50 --- /dev/null +++ b/resources/config/Drupal/11.x/Module/phpstan.neon.dist @@ -0,0 +1,22 @@ +# -------------------------------------- # +# XpertSelect / Tools # +# -------------------------------------- # +# PHPStan configuration file for Drupal # +# packages. # +# -------------------------------------- # + +# This file was generated using XpertSelect/Tools. Please refer to the README for more information. + +parameters: + level: 8 + fileExtensions: + - php + - inc + - module + - theme + - install + paths: + - src + scanDirectories: + - vendor/drupal + tipsOfTheDay: false diff --git a/resources/config/drupal-package/phpunit.xml.dist b/resources/config/Drupal/11.x/Module/phpunit.xml.dist similarity index 98% rename from resources/config/drupal-package/phpunit.xml.dist rename to resources/config/Drupal/11.x/Module/phpunit.xml.dist index 94b5465c9937e3655e6fad33d7db484447c33c46..603adbd80b2219b03b0283850ea912fe754b2ca1 100644 --- a/resources/config/drupal-package/phpunit.xml.dist +++ b/resources/config/Drupal/11.x/Module/phpunit.xml.dist @@ -1,6 +1,6 @@ diff --git a/resources/config/Drupal/11.x/Project/.php-cs-fixer.dist.php b/resources/config/Drupal/11.x/Project/.php-cs-fixer.dist.php new file mode 100644 index 0000000000000000000000000000000000000000..d63a7c199eababc9560d90f5a434e70708307c83 --- /dev/null +++ b/resources/config/Drupal/11.x/Project/.php-cs-fixer.dist.php @@ -0,0 +1,50 @@ +phpCsFixerRuleFile(); + +$rules['header_comment']['header'] = trim(' +This file is part of the ' . $package . ' project. + +This source file is subject to the license that is +bundled with this source code in the LICENSE.md file. +'); + +$finder = Finder::create() + ->in([ + __DIR__ . '/web/modules/custom', + __DIR__ . '/web/profiles/custom', + __DIR__ . '/web/themes/custom', + ]) + ->name('*.inc') + ->name('*.install') + ->name('*.module') + ->name('*.profile') + ->name('*.php') + ->name('*.theme') + ->append([__FILE__]) + ->ignoreDotFiles(false) + ->ignoreVCSIgnored(true); + +return (new Config('XpertSelect/Drupal')) + ->setIndent(' ') + ->setLineEnding("\n") + ->setRules($rules) + ->setFinder($finder); diff --git a/resources/config/Drupal/11.x/Project/.yamllint.yml b/resources/config/Drupal/11.x/Project/.yamllint.yml new file mode 100644 index 0000000000000000000000000000000000000000..672ffc426bc5f39a50017c2e104098f485b1f49b --- /dev/null +++ b/resources/config/Drupal/11.x/Project/.yamllint.yml @@ -0,0 +1,13 @@ +--- +# This file was generated using XpertSelect/Tools. Please refer to the README for more information. + +extends: default + +ignore: | + config/ + +rules: + line-length: + max: 120 + ignore: | + phpstan.neon.dist diff --git a/resources/config/Drupal/11.x/Project/phpstan.neon.dist b/resources/config/Drupal/11.x/Project/phpstan.neon.dist new file mode 100644 index 0000000000000000000000000000000000000000..3053b985027187697db50ab21ebde0b6b1bfc664 --- /dev/null +++ b/resources/config/Drupal/11.x/Project/phpstan.neon.dist @@ -0,0 +1,27 @@ +# -------------------------------------- # +# XpertSelect / Tools # +# -------------------------------------- # +# PHPStan configuration file for Drupal # +# projects. # +# -------------------------------------- # + +# This file was generated using XpertSelect/Tools. Please refer to the README for more information. + +parameters: + level: 8 + fileExtensions: + - php + - inc + - module + - theme + - install + paths: + - web/modules/custom + - web/profiles/custom + - web/themes/custom + scanDirectories: + - web/core + - web/modules/contrib + - web/profiles/contrib + - web/themes/contrib + tipsOfTheDay: false diff --git a/resources/config/drupal-project/phpunit.xml.dist b/resources/config/Drupal/11.x/Project/phpunit.xml.dist similarity index 98% rename from resources/config/drupal-project/phpunit.xml.dist rename to resources/config/Drupal/11.x/Project/phpunit.xml.dist index 3475066bf216b0ffe98f84fb65c94da75bdc3eeb..40584437cdc9b466c11604b9a2ba8649468771a0 100644 --- a/resources/config/drupal-project/phpunit.xml.dist +++ b/resources/config/Drupal/11.x/Project/phpunit.xml.dist @@ -1,6 +1,6 @@ diff --git a/resources/config/standard/.php-cs-fixer.dist.php b/resources/config/Laravel/11.x/Package/.php-cs-fixer.dist.php similarity index 70% rename from resources/config/standard/.php-cs-fixer.dist.php rename to resources/config/Laravel/11.x/Package/.php-cs-fixer.dist.php index 93315dc444dd0d5045625ba2049ad143e017ca0b..dcd9104734f21a920610e1e93e0b908e4c156e2c 100644 --- a/resources/config/standard/.php-cs-fixer.dist.php +++ b/resources/config/Laravel/11.x/Package/.php-cs-fixer.dist.php @@ -9,11 +9,16 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ +use Composer\InstalledVersions; +use PhpCsFixer\Config; +use PhpCsFixer\Finder; +use XpertSelect\Tools\ProjectType; + // This file was generated using XpertSelect/Tools. Please refer to the README for more information. include 'vendor/autoload.php'; -$package = Composer\InstalledVersions::getRootPackage()['name']; -$rules = include XpertSelect\Tools\ProjectType::Standard->phpCsFixerRuleFile(); +$package = InstalledVersions::getRootPackage()['name']; +$rules = include ProjectType::LaravelPackage->phpCsFixerRuleFile(); $rules['header_comment']['header'] = trim(' This file is part of the ' . $package . ' package. @@ -22,13 +27,13 @@ This source file is subject to the license that is bundled with this source code in the LICENSE.md file. '); -$finder = PhpCsFixer\Finder::create() +$finder = Finder::create() ->in([__DIR__]) ->append([__FILE__]) ->ignoreDotFiles(false) ->ignoreVCSIgnored(true); -return (new PhpCsFixer\Config('XpertSelect/PHP')) +return (new Config('XpertSelect/Laravel')) ->setIndent(' ') ->setLineEnding("\n") ->setRules($rules) diff --git a/resources/config/laravel-project/.yamllint.yml b/resources/config/Laravel/11.x/Package/.yamllint.yml similarity index 100% rename from resources/config/laravel-project/.yamllint.yml rename to resources/config/Laravel/11.x/Package/.yamllint.yml diff --git a/resources/config/laravel-package/phpstan.neon.dist b/resources/config/Laravel/11.x/Package/phpstan.neon.dist similarity index 100% rename from resources/config/laravel-package/phpstan.neon.dist rename to resources/config/Laravel/11.x/Package/phpstan.neon.dist diff --git a/resources/config/laravel-package/phpunit.xml.dist b/resources/config/Laravel/11.x/Package/phpunit.xml.dist similarity index 98% rename from resources/config/laravel-package/phpunit.xml.dist rename to resources/config/Laravel/11.x/Package/phpunit.xml.dist index 21fc1d9a1b268ee5e618500d2bd3a889b2d81040..f3da19004199958e8b36f03e09ae584d7cef0255 100644 --- a/resources/config/laravel-package/phpunit.xml.dist +++ b/resources/config/Laravel/11.x/Package/phpunit.xml.dist @@ -1,6 +1,6 @@ diff --git a/resources/config/laravel-project/.php-cs-fixer.dist.php b/resources/config/Laravel/11.x/Project/.php-cs-fixer.dist.php similarity index 70% rename from resources/config/laravel-project/.php-cs-fixer.dist.php rename to resources/config/Laravel/11.x/Project/.php-cs-fixer.dist.php index bbae72d653db2e433458a6279a3cb221b786d652..1891697d4cc07b03bff0d07164933c603a68cd17 100644 --- a/resources/config/laravel-project/.php-cs-fixer.dist.php +++ b/resources/config/Laravel/11.x/Project/.php-cs-fixer.dist.php @@ -9,11 +9,16 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ +use Composer\InstalledVersions; +use PhpCsFixer\Config; +use PhpCsFixer\Finder; +use XpertSelect\Tools\ProjectType; + // This file was generated using XpertSelect/Tools. Please refer to the README for more information. include 'vendor/autoload.php'; -$package = Composer\InstalledVersions::getRootPackage()['name']; -$rules = include XpertSelect\Tools\ProjectType::LaravelProject->phpCsFixerRuleFile(); +$package = InstalledVersions::getRootPackage()['name']; +$rules = include ProjectType::LaravelProject->phpCsFixerRuleFile(); $rules['header_comment']['header'] = trim(' This file is part of the ' . $package . ' package. @@ -22,13 +27,13 @@ This source file is subject to the license that is bundled with this source code in the LICENSE.md file. '); -$finder = PhpCsFixer\Finder::create() +$finder = Finder::create() ->in([__DIR__]) ->append([__FILE__]) ->ignoreDotFiles(false) ->ignoreVCSIgnored(true); -return (new PhpCsFixer\Config('XpertSelect/Laravel')) +return (new Config('XpertSelect/Laravel')) ->setIndent(' ') ->setLineEnding("\n") ->setRules($rules) diff --git a/resources/config/standard/.yamllint.yml b/resources/config/Laravel/11.x/Project/.yamllint.yml similarity index 100% rename from resources/config/standard/.yamllint.yml rename to resources/config/Laravel/11.x/Project/.yamllint.yml diff --git a/resources/config/laravel-project/phpstan.neon.dist b/resources/config/Laravel/11.x/Project/phpstan.neon.dist similarity index 100% rename from resources/config/laravel-project/phpstan.neon.dist rename to resources/config/Laravel/11.x/Project/phpstan.neon.dist diff --git a/resources/config/standard/phpunit.xml.dist b/resources/config/Laravel/11.x/Project/phpunit.xml.dist similarity index 98% rename from resources/config/standard/phpunit.xml.dist rename to resources/config/Laravel/11.x/Project/phpunit.xml.dist index 94b5465c9937e3655e6fad33d7db484447c33c46..603adbd80b2219b03b0283850ea912fe754b2ca1 100644 --- a/resources/config/standard/phpunit.xml.dist +++ b/resources/config/Laravel/11.x/Project/phpunit.xml.dist @@ -1,6 +1,6 @@ diff --git a/resources/config/laravel-package/.php-cs-fixer.dist.php b/resources/config/Standard/.php-cs-fixer.dist.php similarity index 70% rename from resources/config/laravel-package/.php-cs-fixer.dist.php rename to resources/config/Standard/.php-cs-fixer.dist.php index dc558b07b12088b84b403c8417e0d4eccab203c6..fc99f0605efdc4cae2c16d263235c0b20c27ddc4 100644 --- a/resources/config/laravel-package/.php-cs-fixer.dist.php +++ b/resources/config/Standard/.php-cs-fixer.dist.php @@ -9,11 +9,16 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ +use Composer\InstalledVersions; +use PhpCsFixer\Config; +use PhpCsFixer\Finder; +use XpertSelect\Tools\ProjectType; + // This file was generated using XpertSelect/Tools. Please refer to the README for more information. include 'vendor/autoload.php'; -$package = Composer\InstalledVersions::getRootPackage()['name']; -$rules = include XpertSelect\Tools\ProjectType::LaravelPackage->phpCsFixerRuleFile(); +$package = InstalledVersions::getRootPackage()['name']; +$rules = include ProjectType::Standard->phpCsFixerRuleFile(); $rules['header_comment']['header'] = trim(' This file is part of the ' . $package . ' package. @@ -22,13 +27,12 @@ This source file is subject to the license that is bundled with this source code in the LICENSE.md file. '); -$finder = PhpCsFixer\Finder::create() +$finder = Finder::create() ->in([__DIR__]) - ->append([__FILE__]) ->ignoreDotFiles(false) ->ignoreVCSIgnored(true); -return (new PhpCsFixer\Config('XpertSelect/Laravel')) +return (new Config('XpertSelect/PHP')) ->setIndent(' ') ->setLineEnding("\n") ->setRules($rules) diff --git a/resources/config/Standard/.yamllint.yml b/resources/config/Standard/.yamllint.yml new file mode 100644 index 0000000000000000000000000000000000000000..b39bee591f8a30cd9d252f0644fc977026f48c9d --- /dev/null +++ b/resources/config/Standard/.yamllint.yml @@ -0,0 +1,10 @@ +--- +# This file was generated using XpertSelect/Tools. Please refer to the README for more information. + +extends: default + +rules: + line-length: + max: 120 + ignore: | + phpstan.neon.dist diff --git a/resources/config/standard/phpstan.neon.dist b/resources/config/Standard/phpstan.neon.dist similarity index 100% rename from resources/config/standard/phpstan.neon.dist rename to resources/config/Standard/phpstan.neon.dist diff --git a/resources/config/Standard/phpunit.xml.dist b/resources/config/Standard/phpunit.xml.dist new file mode 100644 index 0000000000000000000000000000000000000000..603adbd80b2219b03b0283850ea912fe754b2ca1 --- /dev/null +++ b/resources/config/Standard/phpunit.xml.dist @@ -0,0 +1,36 @@ + + + + + + src + + + vendor + + + + + + + + + + + + + tests/Unit + + + + tests/Functional + + + + + + + diff --git a/resources/config/drupal-package/phive.xml b/resources/config/drupal-package/phive.xml deleted file mode 100644 index dd5925366f7637220ed06cd629a0bdd4bfe62d64..0000000000000000000000000000000000000000 --- a/resources/config/drupal-package/phive.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/config/drupal-project/phive.xml b/resources/config/drupal-project/phive.xml deleted file mode 100644 index dd5925366f7637220ed06cd629a0bdd4bfe62d64..0000000000000000000000000000000000000000 --- a/resources/config/drupal-project/phive.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/config/laravel-package/phive.xml b/resources/config/laravel-package/phive.xml deleted file mode 100644 index a43f512e30b55e210d7051c6667db831f5be23a0..0000000000000000000000000000000000000000 --- a/resources/config/laravel-package/phive.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/config/laravel-project/phive.xml b/resources/config/laravel-project/phive.xml deleted file mode 100644 index a43f512e30b55e210d7051c6667db831f5be23a0..0000000000000000000000000000000000000000 --- a/resources/config/laravel-project/phive.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/config/laravel-project/phpunit.xml.dist b/resources/config/laravel-project/phpunit.xml.dist deleted file mode 100644 index 1754fc6c18bd957d779e9727e94e0f12f66f4ac4..0000000000000000000000000000000000000000 --- a/resources/config/laravel-project/phpunit.xml.dist +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - app - - - vendor - - - - - - - - - - - - - tests/Unit - - - - tests/Functional - - - - - - - - - - - - - - - diff --git a/resources/config/standard/phive.xml b/resources/config/standard/phive.xml deleted file mode 100644 index dd5925366f7637220ed06cd629a0bdd4bfe62d64..0000000000000000000000000000000000000000 --- a/resources/config/standard/phive.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/tools/.gitignore b/resources/tools/.gitignore deleted file mode 100644 index d6b7ef32c8478a48c3994dcadc86837f4371184d..0000000000000000000000000000000000000000 --- a/resources/tools/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/src/App.php b/src/App.php deleted file mode 100644 index 709eca52780637d25654d16bf41cfb5dfa3b64b4..0000000000000000000000000000000000000000 --- a/src/App.php +++ /dev/null @@ -1,90 +0,0 @@ -publisher->publishFiles(); - - return $this; - } - - /** - * Generates the appropriate .gitignore files in the various subdirectories. - * - * @return $this This instance, for method chaining - */ - public function generateGitIgnoreFiles(): self - { - $this->generator->generateGitIgnoreFiles(); - - return $this; - } -} diff --git a/src/PHPUnit/Hooks/BypassFinalHook.php b/src/PHPUnit/Hooks/BypassFinalHook.php new file mode 100644 index 0000000000000000000000000000000000000000..2abe4e5b804848f409935c41e79db8f5ae8d4b1f --- /dev/null +++ b/src/PHPUnit/Hooks/BypassFinalHook.php @@ -0,0 +1,36 @@ +value; + return __DIR__ . '/../resources/config/' . $this->getConfigPathFromValue(); } /** @@ -51,7 +53,6 @@ enum ProjectType: string public function configurationFiles(): array { return [ - 'phive.xml', 'phpstan.neon.dist', 'phpunit.xml.dist', '.php-cs-fixer.dist.php', @@ -75,6 +76,31 @@ enum ProjectType: string }; } + /** + * Converts the value to the correct path to the config. + * + * @return string The path to the config + */ + private function getConfigPathFromValue(): string + { + if ($this->value === ProjectType::Standard->value) { + return 'Standard'; + } + + if (str_contains($this->value, 'laravel')) { + $type = $this->value === ProjectType::LaravelProject->value ? 'Project' : 'Package'; + + return 'Laravel/11.x/' . $type; + } + + $classifierService = new ProjectClassifierService(); + + $drupalVersion = $classifierService->isDrupal10() ? '10.x' : '11.x'; + $type = $this->value === ProjectType::DrupalProject->value ? 'Project' : 'Module'; + + return sprintf('Drupal/%s/%s', $drupalVersion, $type); + } + case Standard = 'standard'; case DrupalProject = 'drupal-project'; case DrupalPackage = 'drupal-package'; diff --git a/src/ConfigurationFilePublisher.php b/src/Services/ConfigurationFilePublisher.php similarity index 65% rename from src/ConfigurationFilePublisher.php rename to src/Services/ConfigurationFilePublisher.php index 4465c7c9e353c359d5ae2a310844a493ef7ec318..a6a200a68bd4ea9f8045410129c1d4b5daf427c6 100644 --- a/src/ConfigurationFilePublisher.php +++ b/src/Services/ConfigurationFilePublisher.php @@ -9,7 +9,9 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ -namespace XpertSelect\Tools; +namespace XpertSelect\Tools\Services; + +use XpertSelect\Tools\ProjectType; /** * Class ConfigurationFilePublisher. @@ -21,13 +23,11 @@ final readonly class ConfigurationFilePublisher /** * ConfigurationFilePublisher constructor. * - * @param ProjectType $projectType The type of project to reason about - * @param string $projectRoot The root of the project - * @param bool $replace Whether to replace previous configuration files - * @param mixed $outputStream The stream to write to + * @param string $projectRoot The root of the project + * @param bool $replace Whether to replace previous configuration files + * @param mixed $outputStream The stream to write to */ - public function __construct(private ProjectType $projectType, - private string $projectRoot, + public function __construct(private string $projectRoot, private bool $replace = false, private mixed $outputStream = STDERR) { @@ -36,10 +36,10 @@ final readonly class ConfigurationFilePublisher /** * Publish all the configuration files offered for the projectType. */ - public function publishFiles(): void + public function publishFiles(ProjectType $projectType): void { - foreach ($this->projectType->configurationFiles() as $file) { - $this->publishFile($file); + foreach ($projectType->configurationFiles() as $file) { + $this->publishFile($file, $projectType); } } @@ -48,7 +48,7 @@ final readonly class ConfigurationFilePublisher * * @param string $file The file to publish */ - public function publishFile(string $file): void + public function publishFile(string $file, ProjectType $projectType): void { $filePath = $this->projectRoot . '/' . $file; @@ -58,7 +58,7 @@ final readonly class ConfigurationFilePublisher return; } - $source = $this->projectType->directory() . '/' . $file; + $source = $projectType->directory() . '/' . $file; $result = copy($source, $filePath); if ($result) { diff --git a/src/Services/DependencyService.php b/src/Services/DependencyService.php new file mode 100644 index 0000000000000000000000000000000000000000..721e3a881828a3f81b15857db3203e20de459a4a --- /dev/null +++ b/src/Services/DependencyService.php @@ -0,0 +1,169 @@ +composerFilePath = empty($composerFilePath) ? Factory::getComposerFile() : $composerFilePath; + } + + /** + * Set the correct dependencies for the given version of the framework. + */ + public function setDependencies(IOInterface $io, Composer $composer): void + { + $composerFile = $this->composerFilePath; + $contents = file_get_contents($composerFile); + + if (false === $contents) { + $io->write('Could not read information in composer file.'); + + return; + } + + $jsonFile = new JsonFile($composerFile); + $currentData = $jsonFile->read(); + + $manipulator = new JsonManipulator($contents); + + $requires = $composer->getPackage()->getDevRequires(); + + foreach ($this->getRequiredDependencies($currentData) as $packageName => $version) { + $currentVersion = $currentData['require-dev'][$packageName] ?? $currentData['require'][$packageName] ?? null; + if (!is_null($currentVersion) && $currentVersion === $version) { + $io->write("{$packageName} already requires version {$version}."); + + continue; + } + if (!is_null($currentVersion)) { + $io->write("{$packageName} already exists with version {$currentVersion}, replacing with {$version}."); + } + + $success = $manipulator->addLink('require-dev', $packageName, $version); + if ($success) { + $io->write("Added {$packageName}:{$version}"); + } else { + $io->write("Failed to add {$packageName}:{$version}"); + } + + $requires[$packageName] = new Link( + $composer->getPackage()->getName(), + $packageName, + new Constraint('>', $version), + 'requires', + $version + ); + } + file_put_contents($composerFile, $manipulator->getContents()); + + $composer->getPackage()->setDevRequires($requires); + + $io->write('All development dependencies are available.' . PHP_EOL); + } + + /** + * Returns the required dependencies for the current project. + * + * @param array $currentData The current data in the composer.json + * + * @return array The required dependencies for the current project, as {packageName => version} + */ + private function getRequiredDependencies(array $currentData): array + { + $dependencies = [ + 'php-cs-fixer/shim' => '^3.89', + 'phpstan/phpstan-strict-rules' => '^2.0', + 'phpunit/phpunit' => '^11.0', + 'mockery/mockery' => '^1.6', + ]; + + if ($this->isLaravel($currentData)) { + $dependencies['larastan/larastan'] = '^3.7'; + $dependencies['wterberg/phpstan-laravel'] = '^2.0'; + $dependencies['nunomaduro/collision'] = '^8.8'; + } + + if ($this->isDrupal10($currentData)) { + $dependencies['phpunit/phpunit'] = '^9.0'; + } + + return $dependencies; + } + + /** + * Checks the current composer json to see if laravel is installed. + * + * @param array $currentData The current data in the composer.json + * + * @return bool If laravel is detected + */ + private function isLaravel(array $currentData): bool + { + foreach (ProjectClassifierService::LARAVEL_DETECTION_DEPENDENCIES as $packageName) { + if (isset($currentData['require'][$packageName])) { + return true; + } + } + + return false; + } + + /** + * Checks the current composer json to see if drupal is installed. + * + * @param array $currentData The current data in the composer.json + * + * @return bool If drupal 10 is detected + */ + private function isDrupal10(array $currentData): bool + { + $version = null; + + foreach (ProjectClassifierService::DRUPAL_DETECTION_DEPENDENCIES as $packageName) { + if (isset($currentData['require'][$packageName])) { + $version = $currentData['require'][$packageName]; + + break; + } + } + + if (is_null($version)) { + return false; + } + + if ('*' === $version) {// The latest version is used + return false; + } + + return str_starts_with($version, '10'); + } +} diff --git a/src/GitIgnoreGenerator.php b/src/Services/GitIgnoreGenerator.php similarity index 73% rename from src/GitIgnoreGenerator.php rename to src/Services/GitIgnoreGenerator.php index c2605ad55da6a11112a18b829641541f5302ebec..ec5cb76048e7dd8b925b14ec3de8684c68a55b16 100644 --- a/src/GitIgnoreGenerator.php +++ b/src/Services/GitIgnoreGenerator.php @@ -9,7 +9,9 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ -namespace XpertSelect\Tools; +namespace XpertSelect\Tools\Services; + +use XpertSelect\Tools\ProjectType; /** * Class GitIgnoreGenerator. @@ -21,12 +23,10 @@ final readonly class GitIgnoreGenerator /** * GitIgnoreGenerator constructor. * - * @param ProjectType $projectType The type of project to reason about - * @param string $projectRoot The root of the project to reason about - * @param mixed $outputStream The stream to write to + * @param string $projectRoot The root of the project + * @param mixed $outputStream The stream to write to */ - public function __construct(private ProjectType $projectType, - private string $projectRoot, + public function __construct(private string $projectRoot, private mixed $outputStream = STDERR) { } @@ -34,29 +34,17 @@ final readonly class GitIgnoreGenerator /** * Generate all the `.gitignore` files for the current project. */ - public function generateGitIgnoreFiles(): void + public function generateGitIgnoreFiles(ProjectType $projectType): void { - $this->generateToolsIgnoreFile(); - $this->generateDrupalIgnoreFiles(); - } - - /** - * Generate the `.gitignore` file for the `resources/tools` directory. - */ - private function generateToolsIgnoreFile(): void - { - $path = $this->projectRoot . '/resources/tools'; - - $this->ensureDirectoryExists($path); - $this->placeIgnoreFile($path, true); + $this->generateDrupalIgnoreFiles($projectType); } /** * Generate the `.gitignore` files required for a Drupal project. */ - private function generateDrupalIgnoreFiles(): void + private function generateDrupalIgnoreFiles(ProjectType $projectType): void { - if ('drupal-project' !== $this->projectType->value) { + if ('drupal-project' !== $projectType->value) { return; } diff --git a/src/Services/ProjectClassifierService.php b/src/Services/ProjectClassifierService.php new file mode 100644 index 0000000000000000000000000000000000000000..63cfaea2d98bcc88e8b15b8b9f428854403f7b69 --- /dev/null +++ b/src/Services/ProjectClassifierService.php @@ -0,0 +1,223 @@ +isLaravel()) { + if ($this->isModuleOrPackage($type)) { + return ProjectType::LaravelPackage; + } + + return ProjectType::LaravelProject; + } + if ($this->isDrupal()) { + if ($this->isModuleOrPackage($type)) { + return ProjectType::DrupalPackage; + } + + return ProjectType::DrupalProject; + } + + return ProjectType::Standard; + } + + /** + * Determines if the composer.json is for a laravel project. + * + * @param string $type The type in the composer json + * + * @return bool If the composer.json is for a laravel project + */ + public function isLaravelProject(string $type): bool + { + return $this->isLaravel() && !$this->isModuleOrPackage($type); + } + + /** + * Determines if the composer.json is for a laravel package. + * + * @param string $type The type in the composer json + * + * @return bool If the composer.json is for a laravel package + */ + public function isLaravelPackage(string $type): bool + { + return $this->isLaravel() && $this->isModuleOrPackage($type); + } + + /** + * Determines if the composer.json is for a drupal project. + * + * @param string $type The type in the composer json + * + * @return bool If the composer.json is for a drupal project + */ + public function isDrupalProject(string $type): bool + { + return $this->isDrupal() && !$this->isModuleOrPackage($type); + } + + /** + * Determines if the composer.json is for a drupal module. + * + * @param string $type The type in the composer json + * + * @return bool If the composer.json is for a drupal module + */ + public function isDrupalModule(string $type): bool + { + return $this->isDrupal() && $this->isModuleOrPackage($type); + } + + /** + * Determines if the composer.json is for a laravel instance. + * + * @return bool If the composer.json is for a laravel instance + */ + public function isLaravel(): bool + { + foreach (self::LARAVEL_DETECTION_DEPENDENCIES as $packageName) { + if ($this->isInstalled($packageName)) { + return true; + } + } + + return false; + } + + /** + * Determines if the composer.json is for a drupal instance. + * + * @return bool If the composer.json is for a drupal instance + */ + public function isDrupal(): bool + { + foreach (self::DRUPAL_DETECTION_DEPENDENCIES as $packageName) { + if ($this->isInstalled($packageName)) { + return true; + } + } + + return false; + } + + /** + * Determines if the composer.json is for a drupal 10 instance. + * + * @return bool If the composer.json is for a drupal 10 instance + */ + public function isDrupal10(): bool + { + foreach (self::DRUPAL_DETECTION_DEPENDENCIES as $packageName) { + if ($this->isVersionInstalled($packageName, '10')) { + return true; + } + } + + return false; + } + + /** + * Determines if the composer.json is for a drupal 11 instance. + * + * @return bool If the composer.json is for a drupal 11 instance + */ + public function isDrupal11(): bool + { + foreach (self::DRUPAL_DETECTION_DEPENDENCIES as $packageName) { + if ($this->isVersionInstalled($packageName, '11')) { + return true; + } + } + + return false; + } + + /** + * Determines if the composer.json contains the given package. + * + * @param string $package The package to check for + * + * @return bool If the composer.json contains the given package + */ + public function isInstalled(string $package): bool + { + return InstalledVersions::isInstalled($package); + } + + /** + * Determines if the composer.json contains the given package with the specific version. + * + * @param string $package The package to check for + * @param string $requiredMajorVersion The exact major version to check for + * + * @return bool If the composer.json contains the given package with the specific version + */ + public function isVersionInstalled(string $package, string $requiredMajorVersion): bool + { + if (!$this->isInstalled($package)) { + return false; + } + + $version = InstalledVersions::getPrettyVersion($package) ?? ''; + + return boolval(preg_match(sprintf('/^%s(\.|-)/', $requiredMajorVersion), $version)); + } + + /** + * Determines if the composer.json has a type for a package or module. + * + * @param string $type The type in the composer.json + * + * @return bool If the composer.json has a type for a package or module + */ + private function isModuleOrPackage(string $type): bool + { + return in_array($type, self::MODULE_OR_PACKAGE_COMPOSER_TYPES); + } +} diff --git a/src/ToolsPlugin.php b/src/ToolsPlugin.php new file mode 100644 index 0000000000000000000000000000000000000000..69e46de30b953f9dd5cd1e200c9b380172022226 --- /dev/null +++ b/src/ToolsPlugin.php @@ -0,0 +1,152 @@ + 'onPostUpdate', + ScriptEvents::PRE_UPDATE_CMD => 'onPreUpdate', + ]; + } + + public function __construct(private readonly ProjectClassifierService $classifierService = new ProjectClassifierService()) + { + } + + /** + * {@inheritdoc} + */ + public function activate(Composer $composer, IOInterface $io): void + { + $projectRoot = $this->getProjectRoot($composer); + $this->dependencyService = new DependencyService(); + $this->configurationFilePublisher = new ConfigurationFilePublisher($projectRoot); + $this->gitIgnoreGenerator = new GitIgnoreGenerator($projectRoot); + } + + /** + * {@inheritdoc} + */ + public function deactivate(Composer $composer, IOInterface $io): void + { + // Not used, but required by interface + } + + /** + * {@inheritdoc} + */ + public function uninstall(Composer $composer, IOInterface $io): void + { + // Not used, but required by interface + } + + /** + * Called when a pre update event is sent. + * + * @param Event $event The pre update event to handle + */ + public function onPreUpdate(Event $event): void + { + $io = $event->getIO(); + + $io->write('Setting up the required dependencies...'); + $this->dependencyService->setDependencies($io, $event->getComposer()); + } + + /** + * Called when a post update event is sent. + * + * @param Event $event The post update event to handle + */ + public function onPostUpdate(Event $event): void + { + $io = $event->getIO(); + $composer = $event->getComposer(); + $type = $composer->getPackage()->getType(); + $projectType = $this->classifierService->getProjectType($type); + + $io->write('Loading the corresponding config...'); + + $this->configurationFilePublisher->publishFiles($projectType); + $this->gitIgnoreGenerator->generateGitIgnoreFiles($projectType); + + $io->write('Setup all the tools successfully!'); + } + + /** + * Gets the project root of the installed package. + * + * @param Composer $composer The composer object with relevant config + * + * @return string The path to the root of the project + */ + private function getProjectRoot(Composer $composer): string + { + $vendorDir = $composer->getConfig()->get('vendor-dir') ?: 'vendor'; + + if (!$this->isAbsolutePath($vendorDir)) { + $composerFile = Factory::getComposerFile(); + $baseDir = dirname($composerFile); + $vendorDir = $baseDir . DIRECTORY_SEPARATOR . $vendorDir; + } + + $vendorDir = realpath($vendorDir) ?: $vendorDir; + + return dirname($vendorDir); + } + + /** + * Checks if the path is an absolute path. + * + * @param string $path The path to check + * + * @return bool True if the path is an absolute path + */ + private function isAbsolutePath(string $path): bool + { + if ('' === $path) { + return false; + } + if ('/' === $path[0]) { + return true; + } + + return preg_match('#^[A-Za-z]:\\\\#', $path) || strpos($path, '\\\\') === 0; + } +} diff --git a/tests/Functional/CLI/XsConfigTest.php b/tests/Functional/CLI/XsConfigTest.php deleted file mode 100644 index 6146388247a901531d22508069d25feab5c60320..0000000000000000000000000000000000000000 --- a/tests/Functional/CLI/XsConfigTest.php +++ /dev/null @@ -1,25 +0,0 @@ -assertTrue(true); - } -} diff --git a/tests/Functional/System/ProjectTypeConfigurationTest.php b/tests/Functional/ProjectTypeConfigurationTest.php similarity index 83% rename from tests/Functional/System/ProjectTypeConfigurationTest.php rename to tests/Functional/ProjectTypeConfigurationTest.php index a17e958faf23229695f751b613fdded54e48a551..6c27c02cdbcbab8bde63fe532292c20f044b1ac0 100644 --- a/tests/Functional/System/ProjectTypeConfigurationTest.php +++ b/tests/Functional/ProjectTypeConfigurationTest.php @@ -9,8 +9,9 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ -namespace Tests\Functional\System; +namespace Tests\Functional; +use PHPUnit\Framework\Attributes\DataProvider; use Tests\ProjectTypesDataset; use Tests\TestCase; use XpertSelect\Tools\ProjectType; @@ -22,17 +23,13 @@ final class ProjectTypeConfigurationTest extends TestCase { use ProjectTypesDataset; - /** - * @dataProvider projectTypes - */ + #[DataProvider('projectTypes')] public function testProjectTypesConfigurationDirectoryExists(ProjectType $projectType): void { $this->assertDirectoryExists($projectType->directory()); } - /** - * @dataProvider projectTypes - */ + #[DataProvider('projectTypes')] public function testProjectTypesConfigurationFilesExist(ProjectType $projectType): void { foreach ($projectType->configurationFiles() as $file) { @@ -40,17 +37,13 @@ final class ProjectTypeConfigurationTest extends TestCase } } - /** - * @dataProvider projectTypes - */ + #[DataProvider('projectTypes')] public function testReferencedRuleFileExists(ProjectType $projectType): void { $this->assertFileExists($projectType->phpCsFixerRuleFile()); } - /** - * @dataProvider projectTypes - */ + #[DataProvider('projectTypes')] public function testRuleFileReturnsAnArray(ProjectType $projectType): void { $rules = include $projectType->phpCsFixerRuleFile(); diff --git a/tests/Functional/System/ConfigurationFilePublisherTest.php b/tests/Functional/Services/ConfigurationFilePublisherTest.php similarity index 81% rename from tests/Functional/System/ConfigurationFilePublisherTest.php rename to tests/Functional/Services/ConfigurationFilePublisherTest.php index aad267a98d593f1fe37510ed28bdb85b56740426..7d74ad7d47686983f435b4358236bdcb4b6df4ce 100644 --- a/tests/Functional/System/ConfigurationFilePublisherTest.php +++ b/tests/Functional/Services/ConfigurationFilePublisherTest.php @@ -9,12 +9,13 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ -namespace Tests\Functional\System; +namespace Tests\Functional\Services; +use PHPUnit\Framework\Attributes\DataProvider; use Tests\ProjectTypesDataset; use Tests\TestCase; -use XpertSelect\Tools\ConfigurationFilePublisher; use XpertSelect\Tools\ProjectType; +use XpertSelect\Tools\Services\ConfigurationFilePublisher; /** * @internal @@ -23,9 +24,7 @@ final class ConfigurationFilePublisherTest extends TestCase { use ProjectTypesDataset; - /** - * @dataProvider projectTypes - */ + #[DataProvider('projectTypes')] public function testConfigurationFilesArePublished(ProjectType $projectType): void { $workingDirectory = $this->createTemporaryDirectory(); @@ -35,13 +34,12 @@ final class ConfigurationFilePublisherTest extends TestCase } $publisher = new ConfigurationFilePublisher( - $projectType, $workingDirectory, false, fopen('php://memory', 'rw') ); - $publisher->publishFiles(); + $publisher->publishFiles($projectType); foreach ($projectType->configurationFiles() as $file) { $this->assertFileExists($workingDirectory . '/' . $file); diff --git a/tests/Functional/Services/DependencyServiceTest.php b/tests/Functional/Services/DependencyServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a5bad58fb8d5eabd1bf354e7a3cb6a1790e4e462 --- /dev/null +++ b/tests/Functional/Services/DependencyServiceTest.php @@ -0,0 +1,158 @@ + [ + ['require' => ['drupal/core' => '10.0.0']], + [ + 'php-cs-fixer/shim' => '^3.89', + 'phpstan/phpstan-strict-rules' => '^2.0', + 'phpunit/phpunit' => '^9.0', + 'mockery/mockery' => '^1.6', + ], + ], + 'Drupal 11 project' => [ + ['require' => ['drupal/core' => '11.0.0']], + [ + 'php-cs-fixer/shim' => '^3.89', + 'phpstan/phpstan-strict-rules' => '^2.0', + 'phpunit/phpunit' => '^11.0', + 'mockery/mockery' => '^1.6', + ], + ], + 'Laravel project' => [ + ['require' => ['laravel/framework' => '12.0.0']], + [ + 'php-cs-fixer/shim' => '^3.89', + 'phpstan/phpstan-strict-rules' => '^2.0', + 'phpunit/phpunit' => '^11.0', + 'mockery/mockery' => '^1.6', + 'larastan/larastan' => '^3.7', + 'wterberg/phpstan-laravel' => '^2.0', + 'nunomaduro/collision' => '^8.8', + ], + ], + 'Generic project' => [ + ['require' => []], + [ + 'php-cs-fixer/shim' => '^3.89', + 'phpstan/phpstan-strict-rules' => '^2.0', + 'phpunit/phpunit' => '^11.0', + 'mockery/mockery' => '^1.6', + ], + ], + ]; + } + + #[DataProvider('dependencyProvider')] + public function testGetRequiredDependencies(array $currentData, array $expected): void + { + $service = new DependencyService(); + $result = $this->invokePrivateMethod($service, 'getRequiredDependencies', [ + 'currentData' => $currentData, + ]); + + $this->assertSame( + $expected, + $result, + sprintf( + 'Failed asserting dependencies for project requiring: %s', + implode(', ', array_keys($currentData['require'] ?? [])) + ) + ); + } + + public function testItAddsNewDependencyToComposerFile(): void + { + $composerFile = tempnam(sys_get_temp_dir(), 'composer'); + file_put_contents($composerFile, json_encode([ + 'require' => [], + 'require-dev' => [], + ])); + + $io = Mockery::mock(IOInterface::class); + $io->shouldReceive('write')->times(5); + + $rootPackage = Mockery::mock(RootPackageInterface::class); + $composer = Mockery::mock(Composer::class); + $composer->shouldReceive('getPackage')->andReturn($rootPackage); + $rootPackage->shouldReceive('getDevRequires')->andReturn([]); + $rootPackage->shouldReceive('getName')->andReturn('testProject'); + $rootPackage->shouldReceive('setDevRequires')->withAnyArgs(); + + $dependencyService = Mockery::mock(DependencyService::class, [$composerFile]) + ->makePartial() + ->shouldAllowMockingProtectedMethods(); + + // Mock JsonFile + JsonManipulator + Mockery::mock('overload:' . JsonFile::class) + ->shouldReceive('read') + ->andReturn(['require' => [], 'require-dev' => []]); + + $mock = Mockery::mock('overload:' . JsonManipulator::class); + + $mock->shouldReceive('addLink') + ->times(4) + ->andReturnTrue(); + $mock->shouldReceive('getContents') + ->andReturn(json_encode([ + 'require-dev' => [ + 'php-cs-fixer/shim' => '^3.89', + 'phpstan/phpstan-strict-rules' => '^2.0', + 'phpunit/phpunit' => '^11.0', + 'mockery/mockery' => '^1.6', + ], + ])); + + // Act + $dependencyService->setDependencies($io, $composer); + + // Assert + $updated = json_decode(file_get_contents($composerFile), true); + $this->assertSame('^3.89', $updated['require-dev']['php-cs-fixer/shim']); + $this->assertSame('^2.0', $updated['require-dev']['phpstan/phpstan-strict-rules']); + $this->assertSame('^11.0', $updated['require-dev']['phpunit/phpunit']); + $this->assertSame('^1.6', $updated['require-dev']['mockery/mockery']); + + Mockery::close(); + @unlink($composerFile); + } + + /** + * Helper for invoking private/protected methods via reflection. + */ + private function invokePrivateMethod(object $object, string $methodName, array $args = []) + { + $reflection = new ReflectionClass($object); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($object, $args); + } +} diff --git a/tests/Functional/System/GitIgnoreGeneratorTest.php b/tests/Functional/Services/GitIgnoreGeneratorTest.php similarity index 70% rename from tests/Functional/System/GitIgnoreGeneratorTest.php rename to tests/Functional/Services/GitIgnoreGeneratorTest.php index f2e39cf719d5f043f6c0a7d1df69c3d24686d065..4215b98a01ecb236996fba0fffa0b9d8b636b25b 100644 --- a/tests/Functional/System/GitIgnoreGeneratorTest.php +++ b/tests/Functional/Services/GitIgnoreGeneratorTest.php @@ -9,33 +9,30 @@ declare(strict_types=1); * bundled with this source code in the LICENSE.md file. */ -namespace Tests\Functional\System; +namespace Tests\Functional\Services; use Tests\TestCase; -use XpertSelect\Tools\GitIgnoreGenerator; use XpertSelect\Tools\ProjectType; +use XpertSelect\Tools\Services\GitIgnoreGenerator; /** * @internal */ final class GitIgnoreGeneratorTest extends TestCase { - public function testToolsIgnoreFileIsGeneratedForStandardProject(): void + public function testNoIgnoreFilesAreGeneratedForStandardProject(): void { $workingDirectory = $this->createTemporaryDirectory(); - $this->assertFileDoesNotExist($workingDirectory . '/resources/tools/.gitignore'); $this->assertDirectoryDoesNotExist($workingDirectory . '/web'); $generator = new GitIgnoreGenerator( - ProjectType::Standard, $workingDirectory, fopen('php://memory', 'rw') ); - $generator->generateGitIgnoreFiles(); + $generator->generateGitIgnoreFiles(ProjectType::Standard); - $this->assertFileExists($workingDirectory . '/resources/tools/.gitignore'); $this->assertDirectoryDoesNotExist($workingDirectory . '/web'); } @@ -43,18 +40,15 @@ final class GitIgnoreGeneratorTest extends TestCase { $workingDirectory = $this->createTemporaryDirectory(); - $this->assertFileDoesNotExist($workingDirectory . '/resources/tools/.gitignore'); $this->assertDirectoryDoesNotExist($workingDirectory . '/web'); $generator = new GitIgnoreGenerator( - ProjectType::DrupalProject, $workingDirectory, fopen('php://memory', 'rw') ); - $generator->generateGitIgnoreFiles(); + $generator->generateGitIgnoreFiles(ProjectType::DrupalProject); - $this->assertFileExists($workingDirectory . '/resources/tools/.gitignore'); $this->assertFileExists($workingDirectory . '/web/modules/contrib/.gitignore'); $this->assertFileExists($workingDirectory . '/web/modules/custom/.gitignore'); $this->assertFileExists($workingDirectory . '/web/profiles/contrib/.gitignore'); diff --git a/tests/Functional/Services/ProjectClassifierServiceTest.php b/tests/Functional/Services/ProjectClassifierServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e6b315ce7da0eb67294be2c9c1df4f652ba031d5 --- /dev/null +++ b/tests/Functional/Services/ProjectClassifierServiceTest.php @@ -0,0 +1,200 @@ + + */ + private static ?array $originalInstalled = null; + + public static function setUpBeforeClass(): void + { + self::$originalInstalled = InstalledVersions::getAllRawData(); + } + + public static function tearDownAfterClass(): void + { + if (null !== self::$originalInstalled) { + InstalledVersions::reload(self::$originalInstalled); + } else { + InstalledVersions::reload([ + 'root' => [ + 'name' => 'tests/root', + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => null, + 'type' => 'project', + 'install_path' => __DIR__, + 'aliases' => [], + 'dev' => true, + ], + 'versions' => [], + ]); + } + } + + protected function tearDown(): void + { + $this->withInstalled([]); + parent::tearDown(); + } + + public function testLaravelProjectDetection(): void + { + $classifierService = new ProjectClassifierService(); + $this->withInstalled([ + 'laravel/framework' => '11.0.0', + ]); + + $type = 'project'; + $result = $classifierService->getProjectType($type); + + self::assertSame(ProjectType::LaravelProject, $result); + self::assertTrue($classifierService->isLaravelProject($type)); + self::assertFalse($classifierService->isLaravelPackage($type)); + self::assertFalse($classifierService->isDrupal()); + } + + public function testLaravelProjectDetectedViaTestbenchToo(): void + { + $classifierService = new ProjectClassifierService(); + $this->withInstalled([ + 'orchestra/testbench' => '9.0.0', + ]); + + $type = 'project'; + $result = $classifierService->getProjectType($type); + + self::assertSame(ProjectType::LaravelProject, $result); + self::assertTrue($classifierService->isLaravel()); + } + + public function testLaravelPackageDetection(): void + { + $classifierService = new ProjectClassifierService(); + $this->withInstalled([ + 'laravel/framework' => '11.0.0', + ]); + + $type = 'library'; + $result = $classifierService->getProjectType($type); + + self::assertSame(ProjectType::LaravelPackage, $result); + self::assertTrue($classifierService->isLaravelPackage($type)); + self::assertFalse($classifierService->isLaravelProject($type)); + } + + public function testDrupalProjectDetection(): void + { + $classifierService = new ProjectClassifierService(); + $this->withInstalled([ + 'drupal/core' => '10.2.3', + ]); + + $type = 'project'; + $result = $classifierService->getProjectType($type); + + self::assertSame(ProjectType::DrupalProject, $result); + self::assertTrue($classifierService->isDrupalProject($type)); + self::assertFalse($classifierService->isDrupalModule($type)); + self::assertFalse($classifierService->isLaravel()); + } + + public function testDrupalModuleDetection(): void + { + $classifierService = new ProjectClassifierService(); + $this->withInstalled([ + 'drupal/core' => '10.2.3', + ]); + + $type = 'drupal-module'; + $result = $classifierService->getProjectType($type); + + self::assertSame(ProjectType::DrupalPackage, $result); + self::assertTrue($classifierService->isDrupalModule($type)); + self::assertFalse($classifierService->isDrupalProject($type)); + } + + public function testDrupalVersionChecks(): void + { + $classifierService = new ProjectClassifierService(); + + $this->withInstalled(['drupal/core' => '10.4.0']); + self::assertTrue($classifierService->isDrupal10()); + self::assertFalse($classifierService->isDrupal11()); + + $this->withInstalled(['drupal/core' => '11.0.0-alpha1']); + self::assertTrue($classifierService->isDrupal11()); + self::assertFalse($classifierService->isDrupal10()); + } + + public function testStandardProjectWhenNothingInstalled(): void + { + $classifierService = new ProjectClassifierService(); + $this->withInstalled([]); + + $type = 'project'; + $result = $classifierService->getProjectType($type); + + self::assertSame(ProjectType::Standard, $result); + self::assertFalse($classifierService->isLaravel()); + self::assertFalse($classifierService->isDrupal()); + } + + /** + * Helper to fake installed packages for this process via InstalledVersions::reload(). + * + * @param array $packages map of package => pretty_version (e.g. 'drupal/core' => '10.2.3') + */ + private function withInstalled(array $packages): void + { + $versions = []; + + foreach ($packages as $name => $pretty) { + $versions[$name] = [ + 'pretty_version' => $pretty, + 'version' => $pretty, + 'reference' => null, + 'type' => 'library', + 'install_path' => __DIR__, + 'aliases' => [], + 'dev_requirement' => false, + ]; + } + + InstalledVersions::reload([ + 'root' => [ + 'name' => 'tests/root', + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => null, + 'type' => 'project', + 'install_path' => __DIR__, + 'aliases' => [], + 'dev' => true, + ], + 'versions' => $versions, + ]); + } +} diff --git a/tests/Unit/AppTest.php b/tests/Unit/AppTest.php deleted file mode 100644 index 751ba16082e3088144ff9fe91e8c21c132800255..0000000000000000000000000000000000000000 --- a/tests/Unit/AppTest.php +++ /dev/null @@ -1,46 +0,0 @@ -getMockBuilder(ConfigurationFilePublisher::class) - ->disableOriginalConstructor() - ->onlyMethods(['publishFiles']) - ->getMock(); - $mockedPublisher->expects($this->once()) - ->method('publishFiles'); - - $mockedGenerator = $this->getMockBuilder(GitIgnoreGenerator::class) - ->disableOriginalConstructor() - ->onlyMethods(['generateGitIgnoreFiles']) - ->getMock(); - $mockedGenerator->expects($this->once()) - ->method('generateGitIgnoreFiles'); - - $app = new App($mockedPublisher, $mockedGenerator); - $app->publishFiles(); - $app->generateGitIgnoreFiles(); - - $this->assertTrue(true); - } -} diff --git a/tests/Unit/ToolsPluginTest.php b/tests/Unit/ToolsPluginTest.php new file mode 100644 index 0000000000000000000000000000000000000000..387031050545a6de43c1ddcab6e7fc0b14162c48 --- /dev/null +++ b/tests/Unit/ToolsPluginTest.php @@ -0,0 +1,183 @@ +classifierService = Mockery::mock(ProjectClassifierService::class); + $this->plugin = new ToolsPlugin($this->classifierService); + } + + public function testGetSubscribedEvents(): void + { + $expected = [ + ScriptEvents::POST_UPDATE_CMD => 'onPostUpdate', + ScriptEvents::PRE_UPDATE_CMD => 'onPreUpdate', + ]; + + self::assertSame($expected, ToolsPlugin::getSubscribedEvents()); + } + + public function testActivateInitializesDependencies(): void + { + $composer = Mockery::mock(Composer::class); + $io = Mockery::mock(IOInterface::class); + $package = Mockery::mock(RootPackageInterface::class); + $config = Mockery::mock(Config::class); + + $package->shouldReceive('getType')->andReturn('project-type'); + $composer->shouldReceive('getPackage')->andReturn($package); + $composer->shouldReceive('getConfig')->andReturn($config); + $config->shouldReceive('get')->with('vendor-dir')->andReturn('vendor'); + + $this->classifierService + ->shouldReceive('getProjectType') + ->andReturn(ProjectType::Standard); + + $this->plugin->activate($composer, $io); + + $ref = new ReflectionClass($this->plugin); + + $depProp = $ref->getProperty('dependencyService'); + $depProp->setAccessible(true); + $confProp = $ref->getProperty('configurationFilePublisher'); + $confProp->setAccessible(true); + $gitProp = $ref->getProperty('gitIgnoreGenerator'); + $gitProp->setAccessible(true); + + self::assertInstanceOf(DependencyService::class, $depProp->getValue($this->plugin)); + self::assertInstanceOf(ConfigurationFilePublisher::class, $confProp->getValue($this->plugin)); + self::assertInstanceOf(GitIgnoreGenerator::class, $gitProp->getValue($this->plugin)); + + Mockery::close(); + } + + public function testOnPreUpdateCallsAllServices(): void + { + $io = Mockery::mock(IOInterface::class); + $composer = Mockery::mock(Composer::class); + $event = Mockery::mock(Event::class); + $event->shouldReceive('getIO')->andReturn($io); + $event->shouldReceive('getComposer')->andReturn($composer); + $composer->shouldReceive('getConfig')->andReturn([]); + + $dependencyService = Mockery::mock(DependencyService::class); + $configPublisher = Mockery::mock(ConfigurationFilePublisher::class); + $gitIgnoreGenerator = Mockery::mock(GitIgnoreGenerator::class); + + $dependencyService->shouldReceive('setDependencies')->once(); + $configPublisher->shouldReceive('publishFiles')->never(); + $gitIgnoreGenerator->shouldReceive('generateGitIgnoreFiles')->never(); + + $messages = []; + $io->shouldReceive('write')->andReturnUsing(function(string $message) use (&$messages) { + $messages[] = $message; + }); + + $ref = new ReflectionClass($this->plugin); + foreach (['dependencyService', 'configurationFilePublisher', 'gitIgnoreGenerator'] as $prop) { + $property = $ref->getProperty($prop); + $property->setAccessible(true); + } + + $ref->getProperty('dependencyService')->setValue($this->plugin, $dependencyService); + $ref->getProperty('configurationFilePublisher')->setValue($this->plugin, $configPublisher); + $ref->getProperty('gitIgnoreGenerator')->setValue($this->plugin, $gitIgnoreGenerator); + + $this->plugin->onPreUpdate($event); + + self::assertSame([ + 'Setting up the required dependencies...', + ], $messages); + } + + public function testOnPostUpdateCallsAllServices(): void + { + $io = Mockery::mock(IOInterface::class); + $composer = Mockery::mock(Composer::class); + $composerConfig = Mockery::mock(Config::class); + $rootPackage = Mockery::mock(RootPackageInterface::class); + $event = Mockery::mock(Event::class); + $event->shouldReceive('getIO')->andReturn($io); + $event->shouldReceive('getComposer')->andReturn($composer); + $composer->shouldReceive('getConfig')->andReturn($composerConfig); + $composer->shouldReceive('getPackage')->andReturn($rootPackage); + $composerConfig->shouldReceive('get')->with('vendor-dir')->andReturn('vendor'); + $rootPackage->shouldReceive('getType')->andReturn('project-type'); + + $this->classifierService->shouldReceive('getProjectType')->andReturn(ProjectType::Standard); + + $dependencyService = Mockery::mock(DependencyService::class); + $configPublisher = Mockery::mock(ConfigurationFilePublisher::class); + $gitIgnoreGenerator = Mockery::mock(GitIgnoreGenerator::class); + + $dependencyService->shouldReceive('setDependencies')->never(); + $configPublisher->shouldReceive('publishFiles')->once(); + $gitIgnoreGenerator->shouldReceive('generateGitIgnoreFiles')->once(); + + $messages = []; + $io->shouldReceive('write')->andReturnUsing(function(string $message) use (&$messages) { + $messages[] = $message; + }); + + $ref = new ReflectionClass($this->plugin); + foreach (['dependencyService', 'configurationFilePublisher', 'gitIgnoreGenerator'] as $prop) { + $property = $ref->getProperty($prop); + $property->setAccessible(true); + } + + $ref->getProperty('dependencyService')->setValue($this->plugin, $dependencyService); + $ref->getProperty('configurationFilePublisher')->setValue($this->plugin, $configPublisher); + $ref->getProperty('gitIgnoreGenerator')->setValue($this->plugin, $gitIgnoreGenerator); + + $this->plugin->onPostUpdate($event); + + self::assertSame([ + 'Loading the corresponding config...', + 'Setup all the tools successfully!', + ], $messages); + } + + public function testIsAbsolutePath(): void + { + $ref = new ReflectionClass($this->plugin); + $method = $ref->getMethod('isAbsolutePath'); + $method->setAccessible(true); + + self::assertTrue($method->invoke($this->plugin, '/usr/local/bin')); + self::assertTrue($method->invoke($this->plugin, 'C:\\Windows')); + self::assertTrue($method->invoke($this->plugin, '\\\\Server\\Share')); + self::assertFalse($method->invoke($this->plugin, 'relative/path')); + self::assertFalse($method->invoke($this->plugin, '')); + } +}