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, ''));
+ }
+}