From d4161832112199a9010dd406f1f6f881102888de Mon Sep 17 00:00:00 2001 From: Alan Brault Date: Sat, 13 Dec 2025 13:12:43 -0500 Subject: [PATCH] refactor: php8.2 support and general performance improvements Signed-off-by: Alan Brault --- .editorconfig | 19 +- .github/workflows/ci.yml | 150 +- .gitignore | 132 +- captainhook.json | 41 +- composer.json | 48 +- composer.lock | 7539 --------------------------- phpbench.json | 27 + phpcs.xml | 384 +- phpstan.neon | 9 +- phpunit.xml | 24 +- psalm.xml | 16 - sonar-project.properties | 4 +- src/Counter.php | 153 +- src/Cuid2.php | 260 +- src/Fingerprint.php | 215 +- src/InvalidOperationException.php | 8 +- src/compat.php | 10 +- tests/CounterTest.php | 152 + tests/Cuid2Test.php | 514 +- tests/FingerprintTest.php | 139 + tests/benchmark/Cuid2Bench.php | 163 + tests/benchmark/SingletonBench.php | 101 + tests/benchmark/ValidationBench.php | 149 + 23 files changed, 2034 insertions(+), 8223 deletions(-) delete mode 100644 composer.lock create mode 100644 phpbench.json delete mode 100644 psalm.xml create mode 100644 tests/CounterTest.php create mode 100644 tests/FingerprintTest.php create mode 100644 tests/benchmark/Cuid2Bench.php create mode 100644 tests/benchmark/SingletonBench.php create mode 100644 tests/benchmark/ValidationBench.php diff --git a/.editorconfig b/.editorconfig index eb17208..ce36d20 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,12 +5,21 @@ charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true - -[*.{md,json}] -indent_style = space indent_size = 4 +indent_style = space + +[*.md] +indent_size = 2 +tab_width = 2 +trim_trailing_whitespace = false + +[*.json] +indent_size = 2 +tab_width = 2 + +[*.{yml,yaml}] +indent_size = 2 +tab_width = 2 [*.php] -indent_style = space -indent_size = 4 max_line_length = 120 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8982a87..fe5a2be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,64 +2,142 @@ name: Continuous Integration on: push: - branches: [main] + branches: + - main + paths-ignore: + - "**.md" + - "renovate.json" + - ".github/ISSUE_TEMPLATE/**" + - ".github/workflows/release.yml" + pull_request: + paths-ignore: + - "**.md" + - "renovate.json" + - ".github/ISSUE_TEMPLATE/**" + - ".github/workflows/release.yml" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - static-analysis: + coding-standards: + name: Coding Standards runs-on: ubuntu-latest + steps: - - uses: actions/checkout@v6 + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 show-progress: false - - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 + + - name: Setup PHP + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: - php-version: '8.4' + php-version: 'latest' tools: composer - extensions: xdebug - - uses: actions/cache@v4 + coverage: none + + - name: Composer Install + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3.1.1 + + - name: Check Syntax + run: composer dev:lint:syntax + + - name: Check Code Style + run: composer dev:lint:style + + static-analysis: + name: Static Analysis + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: - path: | - vendor - ~/.composer/cache - key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }} - restore-keys: composer-${{ runner.os }}- - - run: composer install --quiet --no-ansi --no-interaction --no-progress --prefer-dist - - run: composer normalize --dry-run - - run: composer validate - - run: composer phpstan -- --ansi - - run: composer psalm + fetch-depth: 0 + show-progress: false - unit-tests: - needs: [static-analysis] + - name: Setup PHP + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + with: + php-version: 'latest' + tools: composer + coverage: none + + - name: Composer Install + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3.1.1 + + - name: Run Static Analysis + run: composer dev:analyze:phpstan + + code-coverage: + name: Code Coverage + needs: [coding-standards, static-analysis] runs-on: ubuntu-latest + steps: - - uses: actions/checkout@v6 + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: fetch-depth: 0 show-progress: false - - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 + + - name: Setup PHP + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: - php-version: '8.4' + php-version: 'latest' tools: composer + extensions: gmp coverage: xdebug - - uses: actions/cache@v4 - with: - path: | - vendor - ~/.composer/cache - key: composer-${{ runner.os }}-${{ hashFiles('**/composer.lock') }} - restore-keys: composer-${{ runner.os }}- - - run: composer install --quiet --no-ansi --no-interaction --no-progress --prefer-dist - - run: composer normalize --dry-run - - run: composer validate - - run: vendor/bin/phpunit || true - - uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 + + - name: Composer Install + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3.1.1 + + - name: Run Tests with Coverage + run: composer dev:test:coverage:ci + + - name: Upload to SonarCloud + uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 # 7.0.0 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + unit-tests: + name: Unit Tests + needs: [coding-standards, static-analysis] + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + php-version: ['8.2', '8.3', '8.4', '8.5'] + os: [ubuntu-latest, windows-latest] + + steps: + - name: Configure Git for Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + git config --system core.autocrlf false + git config --system core.eol lf + + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + fetch-depth: 0 + show-progress: false + + - name: Setup PHP + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + with: + php-version: ${{ matrix.php-version }} + tools: composer + extensions: gmp + coverage: none + + - name: Composer Install + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3.1.1 + + - name: Run Unit Tests + run: composer dev:test:unit diff --git a/.gitignore b/.gitignore index 08e8db6..0b2b1ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,131 @@ -# PhpStorm -/.idea/ +##### Operating Systems -# Composer -/vendor +# macOS +.DS_Store +.AppleDouble +.LSOverride +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +# Linux +*~ +.fuse_hidden* +.directory +.Trash-* +.nfs* + +# Windows +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +*.stackdump +[Dd]esktop.ini +$RECYCLE.BIN/ +*.lnk + +##### IDEs and Editors + +# JetBrains (PhpStorm, IntelliJ, etc.) +.idea/ +*.iws +out/ +atlassian-ide-plugin.xml +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace +.history/ + +# Vim +[._]*.s[a-v][a-z] +!*.svg +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] +Session.vim +Sessionx.vim +.netrwhist +tags +[._]*.un~ + +# Emacs +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* +.org-id-locations +*_archive + +# Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache +*.sublime-workspace +sftp-config.json +sftp-config-alt*.json + +##### Backup Files +*.bak +*.gho +*.ori +*.orig +*.tmp + +##### Composer +composer.phar +/vendor/ +composer.lock + +##### PHP Testing & Analysis # PHPUnit -/.phpunit.cache +.phpunit.cache/ .phpunit.result.cache +phpunit.xml + +# Coverage Reports +coverage/ +build/ +*.coverage +clover.xml +coverage.xml +coverage.clover +phpunit-coverage.xml + +# PHPStan +.phpstan.cache/ +.phpstan/ +phpstan.neon.dist + +# PHP-CS-Fixer / CodeSniffer +.php-cs-fixer.cache +.php_cs.cache +/wpcs/* + +# Psalm +.psalm/ +psalm.xml diff --git a/captainhook.json b/captainhook.json index f81134d..c7b30a5 100644 --- a/captainhook.json +++ b/captainhook.json @@ -9,7 +9,11 @@ }, "pre-push": { "enabled": false, - "actions": [] + "actions": [ + { + "action": "composer test" + } + ] }, "pre-commit": { "enabled": true, @@ -41,13 +45,30 @@ ] }, { - "action": "composer phpstan" - }, - { - "action": "composer psalm" + "action": "composer dev:lint:syntax -- {$STAGED_FILES|of-type:php}", + "conditions": [ + { + "exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\OfType", + "args": [ + [ + "php" + ] + ] + } + ] }, { - "action": "XDEBUG_MODE=coverage vendor/bin/phpunit" + "action": "composer dev:lint:style -- {$STAGED_FILES|of-type:php}", + "conditions": [ + { + "exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\OfType", + "args": [ + [ + "php" + ] + ] + } + ] } ] }, @@ -69,8 +90,7 @@ "exec": "\\CaptainHook\\App\\Hook\\Condition\\FileChanged\\Any", "args": [ [ - "composer.json", - "composer.lock" + "composer.json" ] ] } @@ -88,8 +108,7 @@ "exec": "\\CaptainHook\\App\\Hook\\Condition\\FileChanged\\Any", "args": [ [ - "composer.json", - "composer.lock" + "composer.json" ] ] } @@ -105,4 +124,4 @@ "enabled": false, "actions": [] } -} \ No newline at end of file +} diff --git a/composer.json b/composer.json index 0272925..1254e0e 100644 --- a/composer.json +++ b/composer.json @@ -14,23 +14,26 @@ } ], "require": { - "php": "^8.1", + "php": "^8.2", "markrogoyski/math-php": "^2.11", "symfony/polyfill-php83": "^1.32" }, "require-dev": { - "ext-ctype": "*", - "captainhook/captainhook-phar": "^5.23", + "captainhook/captainhook": "^5.27", "captainhook/hook-installer": "^1.0", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^1.2", "ergebnis/composer-normalize": "^2.29", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpbench/phpbench": "^1.4", "phpstan/phpstan": "^1.9", "phpunit/phpunit": "^10.5", "ramsey/conventional-commits": "^1.5", - "squizlabs/php_codesniffer": "^4.0", - "vimeo/psalm": "^6.0" + "slevomat/coding-standard": "^8.25", + "squizlabs/php_codesniffer": "^4.0" }, "suggest": { - "ext-gmp": "Allows for quicker Base16 to Base36 conversion" + "ext-gmp": "Enables faster math with arbitrary precision integers using GMP." }, "minimum-stability": "dev", "prefer-stable": true, @@ -44,13 +47,15 @@ }, "autoload-dev": { "psr-4": { - "Visus\\Cuid2\\Test\\": "tests/" + "Visus\\Cuid2\\Test\\": "tests/", + "Visus\\Cuid2\\Test\\Benchmark\\": "tests/benchmark" } }, "config": { "allow-plugins": { - "captainhook/captainhook-phar": true, "captainhook/hook-installer": true, + "captainhook/plugin-composer": true, + "dealerdirect/phpcodesniffer-composer-installer": true, "ergebnis/composer-normalize": true } }, @@ -60,9 +65,30 @@ } }, "scripts": { - "phpstan": [ - "phpstan analyse -c phpstan.neon --no-progress --memory-limit=1G" + "dev:analyze": [ + "@dev:analyze:phpstan" ], - "psalm": "psalm --show-info=false --config=psalm.xml" + "dev:analyze:phpstan": [ + "phpstan analyse -c phpstan.neon --ansi --memory-limit=1G" + ], + "dev:benchmark": "phpbench run tests/benchmark/ --report=default", + "dev:build:clean": "git clean -fX build/", + "dev:lint": [ + "@dev:lint:syntax", + "@dev:lint:style" + ], + "dev:lint:fix": "phpcbf --cache=build/cache/phpcs.cache", + "dev:lint:style": "phpcs --cache=build/cache/phpcs.cache --colors", + "dev:lint:syntax": "parallel-lint --colors src/ tests/", + "dev:test": [ + "@dev:lint", + "@dev:benchmark", + "@dev:analyze", + "@dev:test:unit" + ], + "dev:test:coverage:ci": "@php -d 'xdebug.mode=coverage' vendor/bin/phpunit --colors=always --coverage-clover build/coverage/xml/clover.xml --log-junit build/coverage/xml/execution.xml", + "dev:test:coverage:html": "@php -d 'xdebug.mode=coverage' vendor/bin/phpunit --colors=always --coverage-html build/coverage/html", + "dev:test:unit": "phpunit --colors=always --no-coverage", + "test": "@dev:test" } } diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 14e06b3..0000000 --- a/composer.lock +++ /dev/null @@ -1,7539 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "09dd9083c36ff0b88cdefdf1c704f7a0", - "packages": [ - { - "name": "markrogoyski/math-php", - "version": "v2.13.0", - "source": { - "type": "git", - "url": "https://github.com/markrogoyski/math-php.git", - "reference": "c064e80bfc4039b812f6b29bacebb07dfb5a049f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/markrogoyski/math-php/zipball/c064e80bfc4039b812f6b29bacebb07dfb5a049f", - "reference": "c064e80bfc4039b812f6b29bacebb07dfb5a049f", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=7.2.0" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phploc/phploc": "*", - "phpmd/phpmd": "^2.6", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.5", - "squizlabs/php_codesniffer": "3.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "MathPHP\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mark Rogoyski", - "email": "mark@rogoyski.com", - "homepage": "https://github.com/markrogoyski", - "role": "Lead developer" - }, - { - "name": "Kevin Nowaczyk", - "homepage": "https://github.com/Beakerboy", - "role": "Developer" - }, - { - "name": "MathPHP Community of Contributors", - "homepage": "https://github.com/markrogoyski/math-php/graphs/contributors" - } - ], - "description": "Math Library for PHP. Features descriptive statistics and regressions; Continuous and discrete probability distributions; Linear algebra with matrices and vectors, Numerical analysis; special mathematical functions; Algebra", - "homepage": "https://github.com/markrogoyski/math-php/", - "keywords": [ - "algebra", - "combinatorics", - "distributions", - "linear algebra", - "math", - "mathematics", - "matrix", - "numerical analysis", - "probability", - "regressions", - "statistics" - ], - "support": { - "issues": "https://github.com/markrogoyski/math-php/issues", - "source": "https://github.com/markrogoyski/math-php/tree/v2.13.0" - }, - "time": "2025-10-24T05:40:38+00:00" - }, - { - "name": "symfony/polyfill-php83", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "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\\Php83\\": "" - }, - "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.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php83/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-07-08T02:45:35+00:00" - } - ], - "packages-dev": [ - { - "name": "amphp/amp", - "version": "v3.1.1", - "source": { - "type": "git", - "url": "https://github.com/amphp/amp.git", - "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", - "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^9", - "psalm/phar": "5.23.1" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php", - "src/Future/functions.php", - "src/Internal/functions.php" - ], - "psr-4": { - "Amp\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - } - ], - "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "https://amphp.org/amp", - "keywords": [ - "async", - "asynchronous", - "awaitable", - "concurrency", - "event", - "event-loop", - "future", - "non-blocking", - "promise" - ], - "support": { - "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.1.1" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-08-27T21:42:00+00:00" - }, - { - "name": "amphp/byte-stream", - "version": "v2.1.2", - "source": { - "type": "git", - "url": "https://github.com/amphp/byte-stream.git", - "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46", - "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/parser": "^1.1", - "amphp/pipeline": "^1", - "amphp/serialization": "^1", - "amphp/sync": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2.3" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "5.22.1" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php", - "src/Internal/functions.php" - ], - "psr-4": { - "Amp\\ByteStream\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A stream abstraction to make working with non-blocking I/O simple.", - "homepage": "https://amphp.org/byte-stream", - "keywords": [ - "amp", - "amphp", - "async", - "io", - "non-blocking", - "stream" - ], - "support": { - "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v2.1.2" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-03-16T17:10:27+00:00" - }, - { - "name": "amphp/cache", - "version": "v2.0.1", - "source": { - "type": "git", - "url": "https://github.com/amphp/cache.git", - "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c", - "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/serialization": "^1", - "amphp/sync": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Amp\\Cache\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - } - ], - "description": "A fiber-aware cache API based on Amp and Revolt.", - "homepage": "https://amphp.org/cache", - "support": { - "issues": "https://github.com/amphp/cache/issues", - "source": "https://github.com/amphp/cache/tree/v2.0.1" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-04-19T03:38:06+00:00" - }, - { - "name": "amphp/dns", - "version": "v2.4.0", - "source": { - "type": "git", - "url": "https://github.com/amphp/dns.git", - "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", - "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/cache": "^2", - "amphp/parser": "^1", - "amphp/process": "^2", - "daverandom/libdns": "^2.0.2", - "ext-filter": "*", - "ext-json": "*", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "5.20" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Amp\\Dns\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Chris Wright", - "email": "addr@daverandom.com" - }, - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - } - ], - "description": "Async DNS resolution for Amp.", - "homepage": "https://github.com/amphp/dns", - "keywords": [ - "amp", - "amphp", - "async", - "client", - "dns", - "resolve" - ], - "support": { - "issues": "https://github.com/amphp/dns/issues", - "source": "https://github.com/amphp/dns/tree/v2.4.0" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-01-19T15:43:40+00:00" - }, - { - "name": "amphp/parallel", - "version": "v2.3.2", - "source": { - "type": "git", - "url": "https://github.com/amphp/parallel.git", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/321b45ae771d9c33a068186b24117e3cd1c48dce", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/cache": "^2", - "amphp/parser": "^1", - "amphp/pipeline": "^1", - "amphp/process": "^2", - "amphp/serialization": "^1", - "amphp/socket": "^2", - "amphp/sync": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.18" - }, - "type": "library", - "autoload": { - "files": [ - "src/Context/functions.php", - "src/Context/Internal/functions.php", - "src/Ipc/functions.php", - "src/Worker/functions.php" - ], - "psr-4": { - "Amp\\Parallel\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Stephen Coakley", - "email": "me@stephencoakley.com" - } - ], - "description": "Parallel processing component for Amp.", - "homepage": "https://github.com/amphp/parallel", - "keywords": [ - "async", - "asynchronous", - "concurrent", - "multi-processing", - "multi-threading" - ], - "support": { - "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.3.2" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-08-27T21:55:40+00:00" - }, - { - "name": "amphp/parser", - "version": "v1.1.1", - "source": { - "type": "git", - "url": "https://github.com/amphp/parser.git", - "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7", - "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7", - "shasum": "" - }, - "require": { - "php": ">=7.4" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Amp\\Parser\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A generator parser to make streaming parsers simple.", - "homepage": "https://github.com/amphp/parser", - "keywords": [ - "async", - "non-blocking", - "parser", - "stream" - ], - "support": { - "issues": "https://github.com/amphp/parser/issues", - "source": "https://github.com/amphp/parser/tree/v1.1.1" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-03-21T19:16:53+00:00" - }, - { - "name": "amphp/pipeline", - "version": "v1.2.3", - "source": { - "type": "git", - "url": "https://github.com/amphp/pipeline.git", - "reference": "7b52598c2e9105ebcddf247fc523161581930367" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", - "reference": "7b52598c2e9105ebcddf247fc523161581930367", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "php": ">=8.1", - "revolt/event-loop": "^1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.18" - }, - "type": "library", - "autoload": { - "psr-4": { - "Amp\\Pipeline\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "Asynchronous iterators and operators.", - "homepage": "https://amphp.org/pipeline", - "keywords": [ - "amp", - "amphp", - "async", - "io", - "iterator", - "non-blocking" - ], - "support": { - "issues": "https://github.com/amphp/pipeline/issues", - "source": "https://github.com/amphp/pipeline/tree/v1.2.3" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-03-16T16:33:53+00:00" - }, - { - "name": "amphp/process", - "version": "v2.0.3", - "source": { - "type": "git", - "url": "https://github.com/amphp/process.git", - "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", - "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/sync": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Amp\\Process\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A fiber-aware process manager based on Amp and Revolt.", - "homepage": "https://amphp.org/process", - "support": { - "issues": "https://github.com/amphp/process/issues", - "source": "https://github.com/amphp/process/tree/v2.0.3" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-04-19T03:13:44+00:00" - }, - { - "name": "amphp/serialization", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/amphp/serialization.git", - "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1", - "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "phpunit/phpunit": "^9 || ^8 || ^7" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Amp\\Serialization\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "Serialization tools for IPC and data storage in PHP.", - "homepage": "https://github.com/amphp/serialization", - "keywords": [ - "async", - "asynchronous", - "serialization", - "serialize" - ], - "support": { - "issues": "https://github.com/amphp/serialization/issues", - "source": "https://github.com/amphp/serialization/tree/master" - }, - "time": "2020-03-25T21:39:07+00:00" - }, - { - "name": "amphp/socket", - "version": "v2.3.1", - "source": { - "type": "git", - "url": "https://github.com/amphp/socket.git", - "reference": "58e0422221825b79681b72c50c47a930be7bf1e1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1", - "reference": "58e0422221825b79681b72c50c47a930be7bf1e1", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/dns": "^2", - "ext-openssl": "*", - "kelunik/certificate": "^1.1", - "league/uri": "^6.5 | ^7", - "league/uri-interfaces": "^2.3 | ^7", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "amphp/process": "^2", - "phpunit/phpunit": "^9", - "psalm/phar": "5.20" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php", - "src/Internal/functions.php", - "src/SocketAddress/functions.php" - ], - "psr-4": { - "Amp\\Socket\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Lowrey", - "email": "rdlowrey@gmail.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.", - "homepage": "https://github.com/amphp/socket", - "keywords": [ - "amp", - "async", - "encryption", - "non-blocking", - "sockets", - "tcp", - "tls" - ], - "support": { - "issues": "https://github.com/amphp/socket/issues", - "source": "https://github.com/amphp/socket/tree/v2.3.1" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-04-21T14:33:03+00:00" - }, - { - "name": "amphp/sync", - "version": "v2.3.0", - "source": { - "type": "git", - "url": "https://github.com/amphp/sync.git", - "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1", - "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/pipeline": "^1", - "amphp/serialization": "^1", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "5.23" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Amp\\Sync\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Stephen Coakley", - "email": "me@stephencoakley.com" - } - ], - "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.", - "homepage": "https://github.com/amphp/sync", - "keywords": [ - "async", - "asynchronous", - "mutex", - "semaphore", - "synchronization" - ], - "support": { - "issues": "https://github.com/amphp/sync/issues", - "source": "https://github.com/amphp/sync/tree/v2.3.0" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-08-03T19:31:26+00:00" - }, - { - "name": "captainhook/captainhook-phar", - "version": "5.27.3", - "source": { - "type": "git", - "url": "https://github.com/captainhook-git/captainhook-phar.git", - "reference": "a5dbcd8d20b3dcdb1cbd6948d0d3a058453b3d6a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/captainhook-git/captainhook-phar/zipball/a5dbcd8d20b3dcdb1cbd6948d0d3a058453b3d6a", - "reference": "a5dbcd8d20b3dcdb1cbd6948d0d3a058453b3d6a", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1||^2.0", - "ext-json": "*", - "ext-spl": "*", - "phar-io/composer-distributor": "^1.0.1", - "php": ">=8.0" - }, - "require-dev": { - "composer/composer": "^1.1 || ^2.0" - }, - "type": "composer-plugin", - "extra": { - "class": "CaptainHook\\Composer\\Plugin" - }, - "autoload": { - "psr-4": { - "CaptainHook\\Composer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Sebastian Feldmann", - "email": "sf@sebastian-feldmann.info" - } - ], - "description": "PHP git hook manager", - "homepage": "https://github.com/captainhook-git/captainhook", - "keywords": [ - "commit-msg", - "git", - "hooks", - "post-merge", - "pre-commit", - "pre-push", - "prepare-commit-msg" - ], - "support": { - "issues": "https://github.com/captainhook-git/captainhook/issues", - "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.27.3" - }, - "funding": [ - { - "url": "https://github.com/sponsors/sebastianfeldmann", - "type": "github" - } - ], - "time": "2025-04-08T07:07:48+00:00" - }, - { - "name": "captainhook/hook-installer", - "version": "1.0.4", - "source": { - "type": "git", - "url": "https://github.com/captainhook-git/hook-installer.git", - "reference": "fb3c45f6204b08baba999f4ffc4ae707bf684e8b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/captainhook-git/hook-installer/zipball/fb3c45f6204b08baba999f4ffc4ae707bf684e8b", - "reference": "fb3c45f6204b08baba999f4ffc4ae707bf684e8b", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1|^2.0", - "php": ">=8.0" - }, - "require-dev": { - "composer/composer": "*" - }, - "type": "composer-plugin", - "extra": { - "class": "CaptainHook\\HookInstaller\\ComposerPlugin" - }, - "autoload": { - "psr-4": { - "CaptainHook\\HookInstaller\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Sebastian Feldmann", - "email": "sf@sebastian-feldmann.info" - } - ], - "description": "Composer Plugin that makes everyone activate the CaptainHook git hooks locally", - "support": { - "issues": "https://github.com/captainhook-git/hook-installer/issues", - "source": "https://github.com/captainhook-git/hook-installer/tree/1.0.4" - }, - "time": "2025-04-08T07:12:26+00:00" - }, - { - "name": "composer/ca-bundle", - "version": "1.5.8", - "source": { - "type": "git", - "url": "https://github.com/composer/ca-bundle.git", - "reference": "719026bb30813accb68271fee7e39552a58e9f65" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/719026bb30813accb68271fee7e39552a58e9f65", - "reference": "719026bb30813accb68271fee7e39552a58e9f65", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "ext-pcre": "*", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8 || ^9", - "psr/log": "^1.0 || ^2.0 || ^3.0", - "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\CaBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", - "keywords": [ - "cabundle", - "cacert", - "certificate", - "ssl", - "tls" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.8" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - } - ], - "time": "2025-08-20T18:49:47+00:00" - }, - { - "name": "composer/class-map-generator", - "version": "1.6.2", - "source": { - "type": "git", - "url": "https://github.com/composer/class-map-generator.git", - "reference": "ba9f089655d4cdd64e762a6044f411ccdaec0076" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/ba9f089655d4cdd64e762a6044f411ccdaec0076", - "reference": "ba9f089655d4cdd64e762a6044f411ccdaec0076", - "shasum": "" - }, - "require": { - "composer/pcre": "^2.1 || ^3.1", - "php": "^7.2 || ^8.0", - "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" - }, - "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-deprecation-rules": "^1 || ^2", - "phpstan/phpstan-phpunit": "^1 || ^2", - "phpstan/phpstan-strict-rules": "^1.1 || ^2", - "phpunit/phpunit": "^8", - "symfony/filesystem": "^5.4 || ^6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\ClassMapGenerator\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" - } - ], - "description": "Utilities to scan PHP code and generate class maps.", - "keywords": [ - "classmap" - ], - "support": { - "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.6.2" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - } - ], - "time": "2025-08-20T18:52:43+00:00" - }, - { - "name": "composer/composer", - "version": "2.8.12", - "source": { - "type": "git", - "url": "https://github.com/composer/composer.git", - "reference": "3e38919bc9a2c3c026f2151b5e56d04084ce8f0b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/3e38919bc9a2c3c026f2151b5e56d04084ce8f0b", - "reference": "3e38919bc9a2c3c026f2151b5e56d04084ce8f0b", - "shasum": "" - }, - "require": { - "composer/ca-bundle": "^1.5", - "composer/class-map-generator": "^1.4.0", - "composer/metadata-minifier": "^1.0", - "composer/pcre": "^2.2 || ^3.2", - "composer/semver": "^3.3", - "composer/spdx-licenses": "^1.5.7", - "composer/xdebug-handler": "^2.0.2 || ^3.0.3", - "justinrainbow/json-schema": "^6.5.1", - "php": "^7.2.5 || ^8.0", - "psr/log": "^1.0 || ^2.0 || ^3.0", - "react/promise": "^3.3", - "seld/jsonlint": "^1.4", - "seld/phar-utils": "^1.2", - "seld/signal-handler": "^2.0", - "symfony/console": "^5.4.47 || ^6.4.25 || ^7.1.10", - "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.1.10", - "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.1.10", - "symfony/polyfill-php73": "^1.24", - "symfony/polyfill-php80": "^1.24", - "symfony/polyfill-php81": "^1.24", - "symfony/process": "^5.4.47 || ^6.4.25 || ^7.1.10" - }, - "require-dev": { - "phpstan/phpstan": "^1.11.8", - "phpstan/phpstan-deprecation-rules": "^1.2.0", - "phpstan/phpstan-phpunit": "^1.4.0", - "phpstan/phpstan-strict-rules": "^1.6.0", - "phpstan/phpstan-symfony": "^1.4.0", - "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3" - }, - "suggest": { - "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", - "ext-zip": "Enabling the zip extension allows you to unzip archives", - "ext-zlib": "Allow gzip compression of HTTP requests" - }, - "bin": [ - "bin/composer" - ], - "type": "library", - "extra": { - "phpstan": { - "includes": [ - "phpstan/rules.neon" - ] - }, - "branch-alias": { - "dev-main": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\": "src/Composer/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "https://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" - } - ], - "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", - "homepage": "https://getcomposer.org/", - "keywords": [ - "autoload", - "dependency", - "package" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/composer/issues", - "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.8.12" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - } - ], - "time": "2025-09-19T11:41:59+00:00" - }, - { - "name": "composer/metadata-minifier", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/composer/metadata-minifier.git", - "reference": "c549d23829536f0d0e984aaabbf02af91f443207" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/metadata-minifier/zipball/c549d23829536f0d0e984aaabbf02af91f443207", - "reference": "c549d23829536f0d0e984aaabbf02af91f443207", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "composer/composer": "^2", - "phpstan/phpstan": "^0.12.55", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\MetadataMinifier\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Small utility library that handles metadata minification and expansion.", - "keywords": [ - "composer", - "compression" - ], - "support": { - "issues": "https://github.com/composer/metadata-minifier/issues", - "source": "https://github.com/composer/metadata-minifier/tree/1.0.0" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2021-04-07T13:37:33+00:00" - }, - { - "name": "composer/pcre", - "version": "3.3.2", - "source": { - "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<1.11.10" - }, - "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8 || ^9" - }, - "type": "library", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - }, - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Pcre\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", - "keywords": [ - "PCRE", - "preg", - "regex", - "regular expression" - ], - "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.2" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2024-11-12T16:29:46+00:00" - }, - { - "name": "composer/semver", - "version": "3.4.4", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.4" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - } - ], - "time": "2025-08-20T19:15:30+00:00" - }, - { - "name": "composer/spdx-licenses", - "version": "1.5.9", - "source": { - "type": "git", - "url": "https://github.com/composer/spdx-licenses.git", - "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/edf364cefe8c43501e21e88110aac10b284c3c9f", - "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Spdx\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "SPDX licenses list and validation library.", - "keywords": [ - "license", - "spdx", - "validator" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.9" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2025-05-12T21:07:07+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "3.0.5", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", - "shasum": "" - }, - "require": { - "composer/pcre": "^1 || ^2 || ^3", - "php": "^7.2.5 || ^8.0", - "psr/log": "^1 || ^2 || ^3" - }, - "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2024-05-06T16:37:16+00:00" - }, - { - "name": "danog/advanced-json-rpc", - "version": "v3.2.2", - "source": { - "type": "git", - "url": "https://github.com/danog/php-advanced-json-rpc.git", - "reference": "aadb1c4068a88c3d0530cfe324b067920661efcb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/danog/php-advanced-json-rpc/zipball/aadb1c4068a88c3d0530cfe324b067920661efcb", - "reference": "aadb1c4068a88c3d0530cfe324b067920661efcb", - "shasum": "" - }, - "require": { - "netresearch/jsonmapper": "^5", - "php": ">=8.1", - "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" - }, - "replace": { - "felixfbecker/php-advanced-json-rpc": "^3" - }, - "require-dev": { - "phpunit/phpunit": "^9" - }, - "type": "library", - "autoload": { - "psr-4": { - "AdvancedJsonRpc\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - }, - { - "name": "Daniil Gentili", - "email": "daniil@daniil.it" - } - ], - "description": "A more advanced JSONRPC implementation", - "support": { - "issues": "https://github.com/danog/php-advanced-json-rpc/issues", - "source": "https://github.com/danog/php-advanced-json-rpc/tree/v3.2.2" - }, - "time": "2025-02-14T10:55:15+00:00" - }, - { - "name": "daverandom/libdns", - "version": "v2.1.0", - "source": { - "type": "git", - "url": "https://github.com/DaveRandom/LibDNS.git", - "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", - "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "Required for IDN support" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "LibDNS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "DNS protocol implementation written in pure PHP", - "keywords": [ - "dns" - ], - "support": { - "issues": "https://github.com/DaveRandom/LibDNS/issues", - "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0" - }, - "time": "2024-04-12T12:12:48+00:00" - }, - { - "name": "dnoegel/php-xdg-base-dir", - "version": "v0.1.1", - "source": { - "type": "git", - "url": "https://github.com/dnoegel/php-xdg-base-dir.git", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" - }, - "type": "library", - "autoload": { - "psr-4": { - "XdgBaseDir\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "implementation of xdg base directory specification for php", - "support": { - "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", - "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" - }, - "time": "2019-12-04T15:06:13+00:00" - }, - { - "name": "doctrine/deprecations", - "version": "1.1.5", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", - "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", - "psr/log": "^1 || ^2 || ^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" - }, - "time": "2025-04-07T20:06:18+00:00" - }, - { - "name": "ergebnis/composer-normalize", - "version": "2.48.2", - "source": { - "type": "git", - "url": "https://github.com/ergebnis/composer-normalize.git", - "reference": "86dc9731b8320f49e9be9ad6d8e4de9b8b0e9b8b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ergebnis/composer-normalize/zipball/86dc9731b8320f49e9be9ad6d8e4de9b8b0e9b8b", - "reference": "86dc9731b8320f49e9be9ad6d8e4de9b8b0e9b8b", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.0.0", - "ergebnis/json": "^1.4.0", - "ergebnis/json-normalizer": "^4.9.0", - "ergebnis/json-printer": "^3.7.0", - "ext-json": "*", - "justinrainbow/json-schema": "^5.2.12 || ^6.0.0", - "localheinz/diff": "^1.3.0", - "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "composer/composer": "^2.8.3", - "ergebnis/license": "^2.7.0", - "ergebnis/php-cs-fixer-config": "^6.53.0", - "ergebnis/phpstan-rules": "^2.11.0", - "ergebnis/phpunit-slow-test-detector": "^2.20.0", - "fakerphp/faker": "^1.24.1", - "infection/infection": "~0.26.6", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^2.1.17", - "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.7", - "phpstan/phpstan-strict-rules": "^2.0.6", - "phpunit/phpunit": "^9.6.20", - "rector/rector": "^2.1.4", - "symfony/filesystem": "^5.4.41" - }, - "type": "composer-plugin", - "extra": { - "class": "Ergebnis\\Composer\\Normalize\\NormalizePlugin", - "branch-alias": { - "dev-main": "2.49-dev" - }, - "plugin-optional": true, - "composer-normalize": { - "indent-size": 2, - "indent-style": "space" - } - }, - "autoload": { - "psr-4": { - "Ergebnis\\Composer\\Normalize\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Andreas Möller", - "email": "am@localheinz.com", - "homepage": "https://localheinz.com" - } - ], - "description": "Provides a composer plugin for normalizing composer.json.", - "homepage": "https://github.com/ergebnis/composer-normalize", - "keywords": [ - "composer", - "normalize", - "normalizer", - "plugin" - ], - "support": { - "issues": "https://github.com/ergebnis/composer-normalize/issues", - "security": "https://github.com/ergebnis/composer-normalize/blob/main/.github/SECURITY.md", - "source": "https://github.com/ergebnis/composer-normalize" - }, - "time": "2025-09-06T11:42:34+00:00" - }, - { - "name": "ergebnis/json", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/ergebnis/json.git", - "reference": "7b56d2b5d9e897e75b43e2e753075a0904c921b1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ergebnis/json/zipball/7b56d2b5d9e897e75b43e2e753075a0904c921b1", - "reference": "7b56d2b5d9e897e75b43e2e753075a0904c921b1", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.44.0", - "ergebnis/data-provider": "^3.3.0", - "ergebnis/license": "^2.5.0", - "ergebnis/php-cs-fixer-config": "^6.37.0", - "ergebnis/phpstan-rules": "^2.11.0", - "ergebnis/phpunit-slow-test-detector": "^2.16.1", - "fakerphp/faker": "^1.24.0", - "infection/infection": "~0.26.6", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^2.1.22", - "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.7", - "phpstan/phpstan-strict-rules": "^2.0.6", - "phpunit/phpunit": "^9.6.24", - "rector/rector": "^2.1.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.7-dev" - }, - "composer-normalize": { - "indent-size": 2, - "indent-style": "space" - } - }, - "autoload": { - "psr-4": { - "Ergebnis\\Json\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Andreas Möller", - "email": "am@localheinz.com", - "homepage": "https://localheinz.com" - } - ], - "description": "Provides a Json value object for representing a valid JSON string.", - "homepage": "https://github.com/ergebnis/json", - "keywords": [ - "json" - ], - "support": { - "issues": "https://github.com/ergebnis/json/issues", - "security": "https://github.com/ergebnis/json/blob/main/.github/SECURITY.md", - "source": "https://github.com/ergebnis/json" - }, - "time": "2025-09-06T09:08:45+00:00" - }, - { - "name": "ergebnis/json-normalizer", - "version": "4.10.1", - "source": { - "type": "git", - "url": "https://github.com/ergebnis/json-normalizer.git", - "reference": "77961faf2c651c3f05977b53c6c68e8434febf62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ergebnis/json-normalizer/zipball/77961faf2c651c3f05977b53c6c68e8434febf62", - "reference": "77961faf2c651c3f05977b53c6c68e8434febf62", - "shasum": "" - }, - "require": { - "ergebnis/json": "^1.2.0", - "ergebnis/json-pointer": "^3.4.0", - "ergebnis/json-printer": "^3.5.0", - "ergebnis/json-schema-validator": "^4.2.0", - "ext-json": "*", - "justinrainbow/json-schema": "^5.2.12 || ^6.0.0", - "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "composer/semver": "^3.4.3", - "ergebnis/composer-normalize": "^2.44.0", - "ergebnis/data-provider": "^3.3.0", - "ergebnis/license": "^2.5.0", - "ergebnis/php-cs-fixer-config": "^6.37.0", - "ergebnis/phpunit-slow-test-detector": "^2.16.1", - "fakerphp/faker": "^1.24.0", - "infection/infection": "~0.26.6", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.10", - "phpstan/phpstan-deprecation-rules": "^1.2.1", - "phpstan/phpstan-phpunit": "^1.4.0", - "phpstan/phpstan-strict-rules": "^1.6.1", - "phpunit/phpunit": "^9.6.19", - "rector/rector": "^1.2.10" - }, - "suggest": { - "composer/semver": "If you want to use ComposerJsonNormalizer or VersionConstraintNormalizer" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.11-dev" - }, - "composer-normalize": { - "indent-size": 2, - "indent-style": "space" - } - }, - "autoload": { - "psr-4": { - "Ergebnis\\Json\\Normalizer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Andreas Möller", - "email": "am@localheinz.com", - "homepage": "https://localheinz.com" - } - ], - "description": "Provides generic and vendor-specific normalizers for normalizing JSON documents.", - "homepage": "https://github.com/ergebnis/json-normalizer", - "keywords": [ - "json", - "normalizer" - ], - "support": { - "issues": "https://github.com/ergebnis/json-normalizer/issues", - "security": "https://github.com/ergebnis/json-normalizer/blob/main/.github/SECURITY.md", - "source": "https://github.com/ergebnis/json-normalizer" - }, - "time": "2025-09-06T09:18:13+00:00" - }, - { - "name": "ergebnis/json-pointer", - "version": "3.7.1", - "source": { - "type": "git", - "url": "https://github.com/ergebnis/json-pointer.git", - "reference": "43bef355184e9542635e35dd2705910a3df4c236" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ergebnis/json-pointer/zipball/43bef355184e9542635e35dd2705910a3df4c236", - "reference": "43bef355184e9542635e35dd2705910a3df4c236", - "shasum": "" - }, - "require": { - "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.43.0", - "ergebnis/data-provider": "^3.2.0", - "ergebnis/license": "^2.4.0", - "ergebnis/php-cs-fixer-config": "^6.32.0", - "ergebnis/phpunit-slow-test-detector": "^2.15.0", - "fakerphp/faker": "^1.23.1", - "infection/infection": "~0.26.6", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.10", - "phpstan/phpstan-deprecation-rules": "^1.2.1", - "phpstan/phpstan-phpunit": "^1.4.0", - "phpstan/phpstan-strict-rules": "^1.6.1", - "phpunit/phpunit": "^9.6.19", - "rector/rector": "^1.2.10" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.8-dev" - }, - "composer-normalize": { - "indent-size": 2, - "indent-style": "space" - } - }, - "autoload": { - "psr-4": { - "Ergebnis\\Json\\Pointer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Andreas Möller", - "email": "am@localheinz.com", - "homepage": "https://localheinz.com" - } - ], - "description": "Provides an abstraction of a JSON pointer.", - "homepage": "https://github.com/ergebnis/json-pointer", - "keywords": [ - "RFC6901", - "json", - "pointer" - ], - "support": { - "issues": "https://github.com/ergebnis/json-pointer/issues", - "security": "https://github.com/ergebnis/json-pointer/blob/main/.github/SECURITY.md", - "source": "https://github.com/ergebnis/json-pointer" - }, - "time": "2025-09-06T09:28:19+00:00" - }, - { - "name": "ergebnis/json-printer", - "version": "3.8.1", - "source": { - "type": "git", - "url": "https://github.com/ergebnis/json-printer.git", - "reference": "211d73fc7ec6daf98568ee6ed6e6d133dee8503e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ergebnis/json-printer/zipball/211d73fc7ec6daf98568ee6ed6e6d133dee8503e", - "reference": "211d73fc7ec6daf98568ee6ed6e6d133dee8503e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.44.0", - "ergebnis/data-provider": "^3.3.0", - "ergebnis/license": "^2.5.0", - "ergebnis/php-cs-fixer-config": "^6.37.0", - "ergebnis/phpunit-slow-test-detector": "^2.16.1", - "fakerphp/faker": "^1.24.0", - "infection/infection": "~0.26.6", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.10", - "phpstan/phpstan-deprecation-rules": "^1.2.1", - "phpstan/phpstan-phpunit": "^1.4.1", - "phpstan/phpstan-strict-rules": "^1.6.1", - "phpunit/phpunit": "^9.6.21", - "rector/rector": "^1.2.10" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.9-dev" - }, - "composer-normalize": { - "indent-size": 2, - "indent-style": "space" - } - }, - "autoload": { - "psr-4": { - "Ergebnis\\Json\\Printer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Andreas Möller", - "email": "am@localheinz.com", - "homepage": "https://localheinz.com" - } - ], - "description": "Provides a JSON printer, allowing for flexible indentation.", - "homepage": "https://github.com/ergebnis/json-printer", - "keywords": [ - "formatter", - "json", - "printer" - ], - "support": { - "issues": "https://github.com/ergebnis/json-printer/issues", - "security": "https://github.com/ergebnis/json-printer/blob/main/.github/SECURITY.md", - "source": "https://github.com/ergebnis/json-printer" - }, - "time": "2025-09-06T09:59:26+00:00" - }, - { - "name": "ergebnis/json-schema-validator", - "version": "4.5.1", - "source": { - "type": "git", - "url": "https://github.com/ergebnis/json-schema-validator.git", - "reference": "b739527a480a9e3651360ad351ea77e7e9019df2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ergebnis/json-schema-validator/zipball/b739527a480a9e3651360ad351ea77e7e9019df2", - "reference": "b739527a480a9e3651360ad351ea77e7e9019df2", - "shasum": "" - }, - "require": { - "ergebnis/json": "^1.2.0", - "ergebnis/json-pointer": "^3.4.0", - "ext-json": "*", - "justinrainbow/json-schema": "^5.2.12 || ^6.0.0", - "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.44.0", - "ergebnis/data-provider": "^3.3.0", - "ergebnis/license": "^2.5.0", - "ergebnis/php-cs-fixer-config": "^6.37.0", - "ergebnis/phpunit-slow-test-detector": "^2.16.1", - "fakerphp/faker": "^1.24.0", - "infection/infection": "~0.26.6", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.10", - "phpstan/phpstan-deprecation-rules": "^1.2.1", - "phpstan/phpstan-phpunit": "^1.4.0", - "phpstan/phpstan-strict-rules": "^1.6.1", - "phpunit/phpunit": "^9.6.20", - "rector/rector": "^1.2.10" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.6-dev" - }, - "composer-normalize": { - "indent-size": 2, - "indent-style": "space" - } - }, - "autoload": { - "psr-4": { - "Ergebnis\\Json\\SchemaValidator\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Andreas Möller", - "email": "am@localheinz.com", - "homepage": "https://localheinz.com" - } - ], - "description": "Provides a JSON schema validator, building on top of justinrainbow/json-schema.", - "homepage": "https://github.com/ergebnis/json-schema-validator", - "keywords": [ - "json", - "schema", - "validator" - ], - "support": { - "issues": "https://github.com/ergebnis/json-schema-validator/issues", - "security": "https://github.com/ergebnis/json-schema-validator/blob/main/.github/SECURITY.md", - "source": "https://github.com/ergebnis/json-schema-validator" - }, - "time": "2025-09-06T11:37:35+00:00" - }, - { - "name": "felixfbecker/language-server-protocol", - "version": "v1.5.3", - "source": { - "type": "git", - "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9", - "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpstan/phpstan": "*", - "squizlabs/php_codesniffer": "^3.1", - "vimeo/psalm": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "LanguageServerProtocol\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - } - ], - "description": "PHP classes for the Language Server Protocol", - "keywords": [ - "language", - "microsoft", - "php", - "server" - ], - "support": { - "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3" - }, - "time": "2024-04-30T00:40:11+00:00" - }, - { - "name": "fidry/cpu-core-counter", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "fidry/makefile": "^0.2.0", - "fidry/php-cs-fixer-config": "^1.1.2", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-deprecation-rules": "^2.0.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^8.5.31 || ^9.5.26", - "webmozarts/strict-phpunit": "^7.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Fidry\\CpuCoreCounter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Théo FIDRY", - "email": "theo.fidry@gmail.com" - } - ], - "description": "Tiny utility to get the number of CPU cores.", - "keywords": [ - "CPU", - "core" - ], - "support": { - "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" - }, - "funding": [ - { - "url": "https://github.com/theofidry", - "type": "github" - } - ], - "time": "2025-08-14T07:29:31+00:00" - }, - { - "name": "jawira/case-converter", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/jawira/case-converter.git", - "reference": "de9956122568743a83e0fc7e2eaa92c1b0de3f18" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jawira/case-converter/zipball/de9956122568743a83e0fc7e2eaa92c1b0de3f18", - "reference": "de9956122568743a83e0fc7e2eaa92c1b0de3f18", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=7.4" - }, - "require-dev": { - "behat/behat": "^3.0", - "phpstan/phpstan": "^v2", - "phpunit/phpunit": "^9.0" - }, - "suggest": { - "pds/skeleton": "PHP Package Development Standards", - "phing/phing": "PHP Build Tool" - }, - "type": "library", - "autoload": { - "psr-4": { - "Jawira\\CaseConverter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jawira Portugal", - "email": "dev@tugal.be" - } - ], - "description": "Convert strings between 13 naming conventions: Snake case, Camel case, Pascal case, Kebab case, Ada case, Train case, Cobol case, Macro case, Upper case, Lower case, Sentence case, Title case and Dot notation.", - "homepage": "https://jawira.github.io/case-converter/", - "keywords": [ - "Ada case", - "Cobol case", - "Macro case", - "Train case", - "camel case", - "dot notation", - "kebab case", - "lower case", - "pascal case", - "sentence case", - "snake case", - "title case", - "upper case" - ], - "support": { - "issues": "https://github.com/jawira/case-converter/issues", - "source": "https://github.com/jawira/case-converter/tree/v3.6.0" - }, - "time": "2025-06-13T21:12:55+00:00" - }, - { - "name": "justinrainbow/json-schema", - "version": "6.5.2", - "source": { - "type": "git", - "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "ac0d369c09653cf7af561f6d91a705bc617a87b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/ac0d369c09653cf7af561f6d91a705bc617a87b8", - "reference": "ac0d369c09653cf7af561f6d91a705bc617a87b8", - "shasum": "" - }, - "require": { - "ext-json": "*", - "marc-mabe/php-enum": "^4.0", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "3.3.0", - "json-schema/json-schema-test-suite": "^23.2", - "marc-mabe/php-enum-phpstan": "^2.0", - "phpspec/prophecy": "^1.19", - "phpstan/phpstan": "^1.12", - "phpunit/phpunit": "^8.5" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.x-dev" - } - }, - "autoload": { - "psr-4": { - "JsonSchema\\": "src/JsonSchema/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/jsonrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "support": { - "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.5.2" - }, - "time": "2025-09-09T09:42:27+00:00" - }, - { - "name": "kelunik/certificate", - "version": "v1.1.3", - "source": { - "type": "git", - "url": "https://github.com/kelunik/certificate.git", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "php": ">=7.0" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^6 | 7 | ^8 | ^9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Kelunik\\Certificate\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "Access certificate details and transform between different formats.", - "keywords": [ - "DER", - "certificate", - "certificates", - "openssl", - "pem", - "x509" - ], - "support": { - "issues": "https://github.com/kelunik/certificate/issues", - "source": "https://github.com/kelunik/certificate/tree/v1.1.3" - }, - "time": "2023-02-03T21:26:53+00:00" - }, - { - "name": "league/uri", - "version": "7.5.1", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", - "shasum": "" - }, - "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" - }, - "conflict": { - "league/uri-schemes": "^1.0" - }, - "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", - "ext-fileinfo": "to create Data URI from file contennts", - "ext-gmp": "to improve IPV4 host parsing", - "ext-intl": "to handle IDN host with the best performance", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", - "php-64bit": "to improve IPV4 host parsing", - "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.x-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Uri\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://nyamsprod.com" - } - ], - "description": "URI manipulation library", - "homepage": "https://uri.thephpleague.com", - "keywords": [ - "data-uri", - "file-uri", - "ftp", - "hostname", - "http", - "https", - "middleware", - "parse_str", - "parse_url", - "psr-7", - "query-string", - "querystring", - "rfc3986", - "rfc3987", - "rfc6570", - "uri", - "uri-template", - "url", - "ws" - ], - "support": { - "docs": "https://uri.thephpleague.com", - "forum": "https://thephpleague.slack.com", - "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" - }, - "funding": [ - { - "url": "https://github.com/sponsors/nyamsprod", - "type": "github" - } - ], - "time": "2024-12-08T08:40:02+00:00" - }, - { - "name": "league/uri-interfaces", - "version": "7.5.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^8.1", - "psr/http-factory": "^1", - "psr/http-message": "^1.1 || ^2.0" - }, - "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", - "ext-gmp": "to improve IPV4 host parsing", - "ext-intl": "to handle IDN host with the best performance", - "php-64bit": "to improve IPV4 host parsing", - "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.x-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Uri\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://nyamsprod.com" - } - ], - "description": "Common interfaces and classes for URI representation and interaction", - "homepage": "https://uri.thephpleague.com", - "keywords": [ - "data-uri", - "file-uri", - "ftp", - "hostname", - "http", - "https", - "parse_str", - "parse_url", - "psr-7", - "query-string", - "querystring", - "rfc3986", - "rfc3987", - "rfc6570", - "uri", - "url", - "ws" - ], - "support": { - "docs": "https://uri.thephpleague.com", - "forum": "https://thephpleague.slack.com", - "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" - }, - "funding": [ - { - "url": "https://github.com/sponsors/nyamsprod", - "type": "github" - } - ], - "time": "2024-12-08T08:18:47+00:00" - }, - { - "name": "localheinz/diff", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/localheinz/diff.git", - "reference": "33bd840935970cda6691c23fc7d94ae764c0734c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/localheinz/diff/zipball/33bd840935970cda6691c23fc7d94ae764c0734c", - "reference": "33bd840935970cda6691c23fc7d94ae764c0734c", - "shasum": "" - }, - "require": { - "php": "~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.5.0 || ^8.5.23", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "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": "Fork of sebastian/diff for use with ergebnis/composer-normalize", - "homepage": "https://github.com/localheinz/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/localheinz/diff/issues", - "source": "https://github.com/localheinz/diff/tree/1.3.0" - }, - "time": "2025-08-30T09:44:18+00:00" - }, - { - "name": "marc-mabe/php-enum", - "version": "v4.7.2", - "source": { - "type": "git", - "url": "https://github.com/marc-mabe/php-enum.git", - "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/bb426fcdd65c60fb3638ef741e8782508fda7eef", - "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef", - "shasum": "" - }, - "require": { - "ext-reflection": "*", - "php": "^7.1 | ^8.0" - }, - "require-dev": { - "phpbench/phpbench": "^0.16.10 || ^1.0.4", - "phpstan/phpstan": "^1.3.1", - "phpunit/phpunit": "^7.5.20 | ^8.5.22 | ^9.5.11", - "vimeo/psalm": "^4.17.0 | ^5.26.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-3.x": "3.2-dev", - "dev-master": "4.7-dev" - } - }, - "autoload": { - "psr-4": { - "MabeEnum\\": "src/" - }, - "classmap": [ - "stubs/Stringable.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Marc Bennewitz", - "email": "dev@mabe.berlin", - "homepage": "https://mabe.berlin/", - "role": "Lead" - } - ], - "description": "Simple and fast implementation of enumerations with native PHP", - "homepage": "https://github.com/marc-mabe/php-enum", - "keywords": [ - "enum", - "enum-map", - "enum-set", - "enumeration", - "enumerator", - "enummap", - "enumset", - "map", - "set", - "type", - "type-hint", - "typehint" - ], - "support": { - "issues": "https://github.com/marc-mabe/php-enum/issues", - "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.2" - }, - "time": "2025-09-14T11:18:39+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": "netresearch/jsonmapper", - "version": "v5.0.0", - "source": { - "type": "git", - "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c", - "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", - "squizlabs/php_codesniffer": "~3.5" - }, - "type": "library", - "autoload": { - "psr-0": { - "JsonMapper": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "OSL-3.0" - ], - "authors": [ - { - "name": "Christian Weiske", - "email": "cweiske@cweiske.de", - "homepage": "http://github.com/cweiske/jsonmapper/", - "role": "Developer" - } - ], - "description": "Map nested JSON structures onto PHP classes", - "support": { - "email": "cweiske@cweiske.de", - "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v5.0.0" - }, - "time": "2024-09-08T10:20:00+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v5.6.1", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "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.1" - }, - "time": "2025-08-13T20:13:15+00:00" - }, - { - "name": "opis/json-schema", - "version": "2.4.1", - "source": { - "type": "git", - "url": "https://github.com/opis/json-schema.git", - "reference": "712827751c62b465daae6e725bf0cf5ffbf965e1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/opis/json-schema/zipball/712827751c62b465daae6e725bf0cf5ffbf965e1", - "reference": "712827751c62b465daae6e725bf0cf5ffbf965e1", - "shasum": "" - }, - "require": { - "ext-json": "*", - "opis/string": "^2.0", - "opis/uri": "^1.0", - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "ext-bcmath": "*", - "ext-intl": "*", - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Opis\\JsonSchema\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Sorin Sarca", - "email": "sarca_sorin@hotmail.com" - }, - { - "name": "Marius Sarca", - "email": "marius.sarca@gmail.com" - } - ], - "description": "Json Schema Validator for PHP", - "homepage": "https://opis.io/json-schema", - "keywords": [ - "json", - "json-schema", - "schema", - "validation", - "validator" - ], - "support": { - "issues": "https://github.com/opis/json-schema/issues", - "source": "https://github.com/opis/json-schema/tree/2.4.1" - }, - "time": "2024-12-30T20:20:21+00:00" - }, - { - "name": "opis/string", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/opis/string.git", - "reference": "ba0b9607b9809462b0e28a11e4881a8d77431feb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/opis/string/zipball/ba0b9607b9809462b0e28a11e4881a8d77431feb", - "reference": "ba0b9607b9809462b0e28a11e4881a8d77431feb", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "ext-json": "*", - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Opis\\String\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Marius Sarca", - "email": "marius.sarca@gmail.com" - }, - { - "name": "Sorin Sarca", - "email": "sarca_sorin@hotmail.com" - } - ], - "description": "Multibyte strings as objects", - "homepage": "https://opis.io/string", - "keywords": [ - "multi-byte", - "opis", - "string", - "string manipulation", - "utf-8" - ], - "support": { - "issues": "https://github.com/opis/string/issues", - "source": "https://github.com/opis/string/tree/2.0.2" - }, - "time": "2024-12-30T21:43:22+00:00" - }, - { - "name": "opis/uri", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/opis/uri.git", - "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/opis/uri/zipball/0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a", - "reference": "0f3ca49ab1a5e4a6681c286e0b2cc081b93a7d5a", - "shasum": "" - }, - "require": { - "opis/string": "^2.0", - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Opis\\Uri\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Marius Sarca", - "email": "marius.sarca@gmail.com" - }, - { - "name": "Sorin Sarca", - "email": "sarca_sorin@hotmail.com" - } - ], - "description": "Build, parse and validate URIs and URI-templates", - "homepage": "https://opis.io", - "keywords": [ - "URI Template", - "parse url", - "punycode", - "uri", - "uri components", - "url", - "validate uri" - ], - "support": { - "issues": "https://github.com/opis/uri/issues", - "source": "https://github.com/opis/uri/tree/1.1.0" - }, - "time": "2021-05-22T15:57:08+00:00" - }, - { - "name": "phar-io/composer-distributor", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/phar-io/composer-distributor.git", - "reference": "dd7d936290b2a42b0c64bfe08090b5c597c280c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/composer-distributor/zipball/dd7d936290b2a42b0c64bfe08090b5c597c280c9", - "reference": "dd7d936290b2a42b0c64bfe08090b5c597c280c9", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1 || ^2.0", - "ext-dom": "*", - "ext-libxml": "*", - "phar-io/filesystem": "^2.0", - "phar-io/gnupg": "^1.0", - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "composer/composer": "^2.0", - "phpunit/phpunit": "^9.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "PharIo\\ComposerDistributor\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Andreas Heigl", - "email": "andreas@heigl.org", - "role": "Developer" - }, - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Feldmann", - "email": "sf@sebastian-feldmann.info", - "role": "Developer" - } - ], - "description": "Base Code for a composer plugin that installs PHAR-files", - "homepage": "https://phar.io", - "keywords": [ - "bin", - "binary", - "composer", - "distribute", - "phar", - "phive" - ], - "support": { - "issues": "https://github.com/phar-io/composer-distributor/issues", - "source": "https://github.com/phar-io/composer-distributor/tree/1.0.2" - }, - "funding": [ - { - "url": "https://phar.io", - "type": "other" - } - ], - "time": "2023-05-31T17:05:49+00:00" - }, - { - "name": "phar-io/executor", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/executor.git", - "reference": "5bfb7400224a0c1cf83343660af85c7f5a073473" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/executor/zipball/5bfb7400224a0c1cf83343660af85c7f5a073473", - "reference": "5bfb7400224a0c1cf83343660af85c7f5a073473", - "shasum": "" - }, - "require": { - "phar-io/filesystem": "^2.0", - "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" - } - ], - "support": { - "issues": "https://github.com/phar-io/executor/issues", - "source": "https://github.com/phar-io/executor/tree/1.0.1" - }, - "time": "2020-11-30T10:53:57+00:00" - }, - { - "name": "phar-io/filesystem", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/filesystem.git", - "reference": "222e3ea432262a05706b7066697c21257664d9d1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/filesystem/zipball/222e3ea432262a05706b7066697c21257664d9d1", - "reference": "222e3ea432262a05706b7066697c21257664d9d1", - "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" - } - ], - "support": { - "issues": "https://github.com/phar-io/filesystem/issues", - "source": "https://github.com/phar-io/filesystem/tree/2.0.1" - }, - "time": "2020-11-30T10:16:22+00:00" - }, - { - "name": "phar-io/gnupg", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/phar-io/gnupg.git", - "reference": "ed8ab1740ac4e9db99500e7252911f2821357093" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/gnupg/zipball/ed8ab1740ac4e9db99500e7252911f2821357093", - "reference": "ed8ab1740ac4e9db99500e7252911f2821357093", - "shasum": "" - }, - "require": { - "phar-io/executor": "^1.0", - "phar-io/filesystem": "^2.0", - "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" - } - ], - "description": "Thin GnuPG wrapper class around the gnupg binary, mimicking the pecl/gnupg api", - "support": { - "issues": "https://github.com/phar-io/gnupg/issues", - "source": "https://github.com/phar-io/gnupg/tree/1.0.3" - }, - "time": "2024-08-22T20:45:57+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": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.6.3", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.1", - "ext-filter": "*", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7|^2.0", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.5 || ~1.6.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "^9.5", - "psalm/phar": "^5.26" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" - }, - "time": "2025-08-01T19:43:32+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.18|^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" - }, - "time": "2024-11-09T15:12:26+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" - }, - "time": "2025-08-30T15:50:23+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.12.32", - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", - "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", - "shasum": "" - }, - "require": { - "php": "^7.2|^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-09-30T10:16:31+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "10.1.16", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.19.1 || ^5.1.0", - "php": ">=8.1", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-text-template": "^3.0.1", - "sebastian/code-unit-reverse-lookup": "^3.0.0", - "sebastian/complexity": "^3.2.0", - "sebastian/environment": "^6.1.0", - "sebastian/lines-of-code": "^2.0.2", - "sebastian/version": "^4.0.1", - "theseer/tokenizer": "^1.2.3" - }, - "require-dev": { - "phpunit/phpunit": "^10.1" - }, - "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": "10.1.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/10.1.16" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-08-22T04:31:57+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "4.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.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": "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/4.1.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-31T06:24:48+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^10.0" - }, - "suggest": { - "ext-pcntl": "*" - }, - "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": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:56:09+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.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": "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/3.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-31T14:07:24+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "6.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.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", - "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", - "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:57:52+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "10.5.60", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f2e26f52f80ef77832e359205f216eeac00e320c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f2e26f52f80ef77832e359205f216eeac00e320c", - "reference": "f2e26f52f80ef77832e359205f216eeac00e320c", - "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.1", - "phpunit/php-code-coverage": "^10.1.16", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-invoker": "^4.0.0", - "phpunit/php-text-template": "^3.0.1", - "phpunit/php-timer": "^6.0.0", - "sebastian/cli-parser": "^2.0.1", - "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.4", - "sebastian/diff": "^5.1.1", - "sebastian/environment": "^6.1.0", - "sebastian/exporter": "^5.1.4", - "sebastian/global-state": "^6.0.2", - "sebastian/object-enumerator": "^5.0.0", - "sebastian/recursion-context": "^5.0.1", - "sebastian/type": "^4.0.0", - "sebastian/version": "^4.0.1" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "10.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/10.5.60" - }, - "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-12-06T07:50:42+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/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+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": "ramsey/conventional-commits", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/ramsey/conventional-commits.git", - "reference": "3eb46b9046d91f5b35462ff770a9d0326601783d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/conventional-commits/zipball/3eb46b9046d91f5b35462ff770a9d0326601783d", - "reference": "3eb46b9046d91f5b35462ff770a9d0326601783d", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.0", - "composer/composer": "^2.4", - "ext-json": "*", - "jawira/case-converter": "^3.5", - "opis/json-schema": "^2.3", - "php": "^8.1", - "symfony/console": "^6.0 || ^7.0", - "symfony/filesystem": "^6.0 || ^7.0" - }, - "require-dev": { - "captainhook/captainhook": "^5.15", - "captainhook/plugin-composer": "^5.3", - "ergebnis/composer-normalize": "^2.30", - "hamcrest/hamcrest-php": "^2.0", - "mockery/mockery": "^1.5", - "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/extension-installer": "^1.2", - "phpstan/phpstan": "^1.10", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^10.1", - "ramsey/coding-standard": "^2.3", - "ramsey/composer-repl": "^1.4", - "roave/security-advisories": "dev-latest", - "sebastianfeldmann/cli": "^3.4", - "sebastianfeldmann/git": "^3.8", - "spatie/phpunit-snapshot-assertions": "^5.1", - "symfony/process": "^6.0 || ^7.0" - }, - "suggest": { - "captainhook/captainhook": "Manage your project's Git hooks with CaptainHook, and use ramsey/conventional-commits in your commit-msg and prepare-commit-msg hooks." - }, - "bin": [ - "bin/conventional-commits" - ], - "type": "library", - "extra": { - "captainhook": { - "force-install": true - }, - "branch-alias": { - "dev-main": "1.x-dev" - }, - "ramsey/conventional-commits": { - "configFile": "conventional-commits.json" - } - }, - "autoload": { - "psr-4": { - "Ramsey\\CaptainHook\\": "src/CaptainHook/", - "Ramsey\\ConventionalCommits\\": "src/ConventionalCommits/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - } - ], - "description": "A PHP library for creating and validating commit messages according to the Conventional Commits specification. Includes a CaptainHook action!", - "keywords": [ - "HOOK", - "captainhook", - "commit", - "commit-msg", - "conventional", - "conventional-commits", - "git", - "plugin" - ], - "support": { - "issues": "https://github.com/ramsey/conventional-commits/issues", - "source": "https://github.com/ramsey/conventional-commits/tree/1.6.0" - }, - "funding": [ - { - "url": "https://github.com/ramsey", - "type": "github" - } - ], - "time": "2025-03-01T19:18:27+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": "revolt/event-loop", - "version": "v1.0.7", - "source": { - "type": "git", - "url": "https://github.com/revoltphp/event-loop.git", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "ext-json": "*", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.15" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Revolt\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - }, - { - "name": "Christian Lück", - "email": "christian@clue.engineering" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "Rock-solid event loop for concurrent PHP applications.", - "keywords": [ - "async", - "asynchronous", - "concurrency", - "event", - "event-loop", - "non-blocking", - "scheduler" - ], - "support": { - "issues": "https://github.com/revoltphp/event-loop/issues", - "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" - }, - "time": "2025-01-25T19:27:39+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.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/2.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:12:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.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", - "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:58:43+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.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" - } - ], - "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", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:59:15+00:00" - }, - { - "name": "sebastian/comparator", - "version": "5.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/diff": "^5.0", - "sebastian/exporter": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.5" - }, - "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" - }, - { - "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/5.0.4" - }, - "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-09-07T05:25:07+00:00" - }, - { - "name": "sebastian/complexity", - "version": "3.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68ff824baeae169ec9f2137158ee529584553799" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", - "reference": "68ff824baeae169ec9f2137158ee529584553799", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.2-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/3.2.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-21T08:37:17+00:00" - }, - { - "name": "sebastian/diff", - "version": "5.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0", - "symfony/process": "^6.4" - }, - "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" - }, - { - "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/5.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:15:17+00:00" - }, - { - "name": "sebastian/environment", - "version": "6.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.1-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/6.1.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-23T08:47:14+00:00" - }, - { - "name": "sebastian/exporter", - "version": "5.1.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "0735b90f4da94969541dac1da743446e276defa6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6", - "reference": "0735b90f4da94969541dac1da743446e276defa6", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.5" - }, - "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" - }, - { - "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/5.1.4" - }, - "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:09:11+00:00" - }, - { - "name": "sebastian/global-state", - "version": "6.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^10.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": "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/6.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:19:19+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.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/2.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-21T08:38:20+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "5.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.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" - } - ], - "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", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:08:32+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.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" - } - ], - "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", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:06:18+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "5.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a", - "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.5" - }, - "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" - }, - { - "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/5.0.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/recursion-context", - "type": "tidelift" - } - ], - "time": "2025-08-10T07:50:56+00:00" - }, - { - "name": "sebastian/type", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.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": "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", - "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:10:45+00:00" - }, - { - "name": "sebastian/version", - "version": "4.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "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 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", - "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-07T11:34:05+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": "spatie/array-to-xml", - "version": "3.4.0", - "source": { - "type": "git", - "url": "https://github.com/spatie/array-to-xml.git", - "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67", - "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": "^8.0" - }, - "require-dev": { - "mockery/mockery": "^1.2", - "pestphp/pest": "^1.21", - "spatie/pest-plugin-snapshots": "^1.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Spatie\\ArrayToXml\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://freek.dev", - "role": "Developer" - } - ], - "description": "Convert an array to xml", - "homepage": "https://github.com/spatie/array-to-xml", - "keywords": [ - "array", - "convert", - "xml" - ], - "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.4.0" - }, - "funding": [ - { - "url": "https://spatie.be/open-source/support-us", - "type": "custom" - }, - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2024-12-16T12:45:15+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "4.0.1", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "0525c73950de35ded110cffafb9892946d7771b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0525c73950de35ded110cffafb9892946d7771b5", - "reference": "0525c73950de35ded110cffafb9892946d7771b5", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=7.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^8.4.0 || ^9.3.4 || ^10.5.32 || 11.3.3 - 11.5.28 || ^11.5.31" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-11-10T16:43:36+00:00" - }, - { - "name": "symfony/console", - "version": "v7.3.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", - "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.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-22T15:31:00+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.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "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.2" - }, - "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-07T08:17:47+00:00" - }, - { - "name": "symfony/finder", - "version": "v7.3.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", - "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.2" - }, - "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-15T13:41:35+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": "symfony/polyfill-php81", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "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\\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/polyfill-php84", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", - "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\\Php84\\": "" - }, - "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.4+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php84/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-24T13:30:11+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.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "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-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "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": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-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": "2025-04-25T09:37:31+00:00" - }, - { - "name": "symfony/string", - "version": "v7.3.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", - "shasum": "" - }, - "require": { - "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": { - "symfony/translation-contracts": "<2.5" - }, - "require-dev": { - "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": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "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" - }, - { - "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-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": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:36:25+00:00" - }, - { - "name": "vimeo/psalm", - "version": "6.14.2", - "source": { - "type": "git", - "url": "https://github.com/vimeo/psalm.git", - "reference": "bbd217fc98c0daa0a13aea2a7f119d03ba3fc9a0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/bbd217fc98c0daa0a13aea2a7f119d03ba3fc9a0", - "reference": "bbd217fc98c0daa0a13aea2a7f119d03ba3fc9a0", - "shasum": "" - }, - "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/parallel": "^2.3", - "composer-runtime-api": "^2", - "composer/semver": "^1.4 || ^2.0 || ^3.0", - "composer/xdebug-handler": "^2.0 || ^3.0", - "danog/advanced-json-rpc": "^3.1", - "dnoegel/php-xdg-base-dir": "^0.1.1", - "ext-ctype": "*", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "felixfbecker/language-server-protocol": "^1.5.3", - "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", - "netresearch/jsonmapper": "^5.0", - "nikic/php-parser": "^5.0.0", - "php": "~8.1.31 || ~8.2.27 || ~8.3.16 || ~8.4.3 || ~8.5.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0 || ^7.0", - "spatie/array-to-xml": "^2.17.0 || ^3.0", - "symfony/console": "^6.0 || ^7.0", - "symfony/filesystem": "~6.3.12 || ~6.4.3 || ^7.0.3", - "symfony/polyfill-php84": "^1.31.0" - }, - "provide": { - "psalm/psalm": "self.version" - }, - "require-dev": { - "amphp/phpunit-util": "^3", - "bamarni/composer-bin-plugin": "^1.4", - "brianium/paratest": "^6.9", - "danog/class-finder": "^0.4.8", - "dg/bypass-finals": "^1.5", - "ext-curl": "*", - "mockery/mockery": "^1.5", - "nunomaduro/mock-final-classes": "^1.1", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpdoc-parser": "^1.6", - "phpunit/phpunit": "^9.6", - "psalm/plugin-mockery": "^1.1", - "psalm/plugin-phpunit": "^0.19", - "slevomat/coding-standard": "^8.4", - "squizlabs/php_codesniffer": "^3.6", - "symfony/process": "^6.0 || ^7.0" - }, - "suggest": { - "ext-curl": "In order to send data to shepherd", - "ext-igbinary": "^2.0.5 is required, used to serialize caching data" - }, - "bin": [ - "psalm", - "psalm-language-server", - "psalm-plugin", - "psalm-refactor", - "psalm-review", - "psalter" - ], - "type": "project", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev", - "dev-2.x": "2.x-dev", - "dev-3.x": "3.x-dev", - "dev-4.x": "4.x-dev", - "dev-5.x": "5.x-dev", - "dev-6.x": "6.x-dev", - "dev-master": "7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psalm\\": "src/Psalm/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthew Brown" - }, - { - "name": "Daniil Gentili", - "email": "daniil@daniil.it" - } - ], - "description": "A static analysis tool for finding errors in PHP applications", - "keywords": [ - "code", - "inspection", - "php", - "static analysis" - ], - "support": { - "docs": "https://psalm.dev/docs", - "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm" - }, - "time": "2025-12-11T08:58:52+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" - }, - "time": "2022-06-03T18:03:27+00:00" - } - ], - "aliases": [], - "minimum-stability": "dev", - "stability-flags": {}, - "prefer-stable": true, - "prefer-lowest": false, - "platform": { - "php": "^8.1" - }, - "platform-dev": { - "ext-ctype": "*" - }, - "plugin-api-version": "2.9.0" -} diff --git a/phpbench.json b/phpbench.json new file mode 100644 index 0000000..c73d2a1 --- /dev/null +++ b/phpbench.json @@ -0,0 +1,27 @@ +{ + "$schema": "./vendor/phpbench/phpbench/phpbench.schema.json", + "runner.bootstrap": "vendor/autoload.php", + "runner.path": "tests/benchmark", + "runner.php_config": { + "memory_limit": "1G" + }, + "report.generators": { + "default": { + "extends": "aggregate", + "cols": [ + "benchmark", + "subject", + "set", + "revs", + "its", + "mem_peak", + "best", + "mean", + "mode", + "worst", + "stdev", + "rstdev" + ] + } + } +} diff --git a/phpcs.xml b/phpcs.xml index c91dea3..47abfb9 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,7 +1,387 @@ + Coding standard for Visus CUID2 PHP library. + + + + + + src + tests + */vendor/* - - \ No newline at end of file + + + + + + + + + + error + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + + diff --git a/phpstan.neon b/phpstan.neon index 29a11a9..049fe2d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,12 @@ +includes: + - vendor/phpstan/phpstan/conf/bleedingEdge.neon + parameters: + tmpDir: ./build/cache/phpstan level: max + treatPhpDocTypesAsCertain: false paths: - src - - tests \ No newline at end of file + - tests + excludePaths: + - vendor diff --git a/phpunit.xml b/phpunit.xml index 7a7ee75..93a561e 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,22 +1,16 @@ + cacheDirectory=".phpunit.cache" + failOnWarning="true" + failOnRisky="true" + beStrictAboutOutputDuringTests="true"> - + tests - - - - - - - - - src @@ -25,7 +19,7 @@ src/compat.php - - - + + + diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index 5d7adfd..0000000 --- a/psalm.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - diff --git a/sonar-project.properties b/sonar-project.properties index d29d698..e90a0a5 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -6,5 +6,5 @@ sonar.projectBaseDir=. sonar.sources=src sonar.tests=tests -sonar.php.coverage.reportPaths=build/logs/clover.xml -sonar.php.tests.reportPath=build/logs/execution.xml \ No newline at end of file +sonar.php.coverage.reportPaths=build/coverage/xml/clover.xml +sonar.php.tests.reportPath=build/coverage/xml/execution.xml diff --git a/src/Counter.php b/src/Counter.php index acf4aa4..b2b4c08 100644 --- a/src/Counter.php +++ b/src/Counter.php @@ -5,66 +5,129 @@ namespace Visus\Cuid2; use Exception; +use Random\Engine\Secure; +use Random\Randomizer; /** - * Singleton responsible for keeping track of iterations. + * Singleton responsible for maintaining a monotonically increasing counter for CUID2 generation. + * + * This class prevents collisions when generating multiple CUIDs in rapid succession within the same + * process. The counter is initialized with a cryptographically secure random value and increments + * with each CUID generated. + * + * The counter uses a bias-free random initialization algorithm to ensure uniform distribution + * within the RANGE (0 to 476782367). When the counter reaches RANGE, it wraps back to 0 to + * prevent integer overflow in long-running processes. + * + * Thread Safety: + * - In PHP, each request/process maintains its own singleton instance + * - The singleton pattern ensures consistency within a single process lifecycle + * - Different processes will have different counter values (by design) + * + * Singleton Protections: + * - Cannot be cloned (__clone is private) + * - Cannot be unserialized (__wakeup throws exception) + * - Cannot be directly instantiated (constructor is private) + * + * @internal This class is internal to the CUID2 library and should not be used directly. * - * @internal * @psalm-internal Visus\Cuid2 */ final class Counter { /** * The range for the counter value. + * * 476782367 is chosen to provide a large enough space for unique values while fitting within * the constraints of the CUID2 specification. This value is derived from the maximum safe * integer range for the algorithm, ensuring uniform distribution and minimizing bias when - * generating random values. See https://github.com/paralleldrive/cuid2 for details. + * generating random values. + * + * The counter wraps back to 0 when this value is reached to prevent integer overflow. + * + * @see https://github.com/paralleldrive/cuid2 CUID2 specification */ private const RANGE = 476782367; - private const MAX_ATTEMPTS = 1000; - + /** + * The singleton instance. + */ private static ?Counter $instance = null; /** + * The current counter value. + * + * Initialized with a cryptographically secure random value in the range [0, RANGE) and + * increments with each call to getNextValue(). Wraps back to 0 when RANGE is reached. + * * @psalm-readonly-allow-private-mutation */ private int $value; + /** + * Initializes the counter with a cryptographically secure random value. + * + * Uses PHP 8.2's Random extension with the Secure engine, which provides + * cryptographically secure random number generation with automatic bias-free + * sampling. This eliminates the need for manual rejection sampling algorithms. + * + * The Randomizer handles: + * - CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) + * - Bias-free integer generation via internal rejection sampling + * - Uniform distribution within the specified range + * + * @throws Exception If the random source is unavailable (extremely rare in PHP 8.2+). + */ private function __construct() { - $max = PHP_INT_MAX - (PHP_INT_MAX % self::RANGE); - - // Fallback: If the bias-free range is insufficient (i.e., max is less than half of PHP_INT_MAX), - // use a simple modulus operation, which may introduce bias but is acceptable as a last resort. - // The threshold of half PHP_INT_MAX is chosen because, for values of $max below this, - // the probability of bias in the modulus operation increases significantly, and the - // number of attempts required for bias-free sampling may become impractically large. - // This is a pragmatic balance between statistical correctness and performance. - if ($max < PHP_INT_MAX / 2) { - $this->value = random_int(0, PHP_INT_MAX) % self::RANGE; - return; - } - - $attempts = -1; - - do { - if (++$attempts > self::MAX_ATTEMPTS) { - $this->value = random_int(0, PHP_INT_MAX) % self::RANGE; - return; - } + $randomizer = new Randomizer(new Secure()); + $this->value = $randomizer->getInt(0, self::RANGE - 1); + } - $randomInt = random_int(0, PHP_INT_MAX); - } while ($randomInt >= $max); + /** + * Prevents cloning of the singleton instance. + * + * Cloning would break the singleton pattern and could lead to inconsistent counter + * states, potentially causing CUID collisions. This method is intentionally private + * and empty to prevent cloning attempts. + * + * @codeCoverageIgnore + */ + private function __clone(): void + { + // Prevent cloning + } - $this->value = $randomInt % self::RANGE; + /** + * Prevents unserialization of the singleton instance. + * + * Unserializing would create a new instance with a potentially outdated counter value, + * breaking the singleton pattern and risking CUID collisions. This method throws an + * exception if unserialization is attempted. + * + * @throws InvalidOperationException Always thrown to prevent unserialization. + */ + public function __wakeup(): void + { + throw new InvalidOperationException('Cannot unserialize singleton'); } /** - * Gets the current instance. + * Gets or creates the singleton Counter instance. + * + * This method implements lazy initialization - the Counter is only created when first + * accessed. Subsequent calls return the same instance, ensuring a consistent counter + * value throughout the process lifecycle. + * + * Usage: + * ```php + * $counter = Counter::getInstance(); + * $value = $counter->getNextValue(); + * ``` + * + * @return Counter The singleton Counter instance. * - * @return Counter + * @throws Exception If the random source is unavailable during first initialization. */ public static function getInstance(): Counter { @@ -72,12 +135,36 @@ public static function getInstance(): Counter } /** - * Gets the next value from the current instance. + * Returns the current counter value and increments it for the next call. * - * @return int + * This method is the core of collision prevention in CUID2 generation. Each call + * returns a unique value within the current process, ensuring CUIDs generated in + * rapid succession have different counter components. + * + * The counter automatically wraps back to 0 when it reaches RANGE (476782367), + * preventing integer overflow in long-running processes while maintaining uniqueness + * through other CUID components (timestamp, random, fingerprint). + * + * Behavior: + * - Returns current value + * - Increments internal counter + * - Wraps to 0 at RANGE boundary + * + * Usage: + * ```php + * $counter = Counter::getInstance(); + * $val1 = $counter->getNextValue(); // e.g., 123456 + * $val2 = $counter->getNextValue(); // e.g., 123457 + * $val3 = $counter->getNextValue(); // e.g., 123458 + * ``` + * + * @return int The current counter value before incrementing (range: 0 to RANGE-1). */ public function getNextValue(): int { - return $this->value++; + $value = $this->value; + $this->value = ($this->value + 1) % self::RANGE; + + return $value; } } diff --git a/src/Cuid2.php b/src/Cuid2.php index 4448206..2cb9759 100644 --- a/src/Cuid2.php +++ b/src/Cuid2.php @@ -4,7 +4,6 @@ namespace Visus\Cuid2; -use DateTime; use Exception; use JsonSerializable; use MathPHP\Exception\BadParameterException; @@ -12,66 +11,133 @@ use OutOfRangeException; use Override; +/** + * Generates collision-resistant, URL-safe unique identifiers (CUID2). + * + * This class implements the CUID2 specification to generate unique, sortable identifiers + * that are more secure and collision-resistant than traditional UUIDs. Each CUID consists of: + * - Random lowercase letter prefix (a-z) + * - Timestamp in milliseconds (collision prevention across time) + * - Monotonic counter (collision prevention in rapid succession) + * - Machine/process fingerprint (uniqueness across machines) + * - Cryptographically secure random data + * + * All components are hashed with SHA3-512 and converted to base36 for the final identifier. + * + * Performance Characteristics: + * - CUID value generated immediately during construction + * - Value cached for zero-overhead repeated access + * - Binary data stored directly (no pack/unpack overhead) + * - High-resolution timestamp using hrtime() + * - Immutable once constructed + * + * Example: + * ```php + * $cuid = new Cuid2(); // Default 24 characters + * $short = new Cuid2(10); // Shorter 10 character ID + * echo $cuid; // e.g., "tz4a98xxat96iws9zmbrgj3a" + * ``` + * + * @see https://github.com/paralleldrive/cuid2 CUID2 specification + */ final class Cuid2 implements JsonSerializable { + /** + * Base36 alphabet used for encoding (0-9, a-z). + */ public const BASE36_ALPHANUMERIC = '0123456789abcdefghijklmnopqrstuvwxyz'; /** + * Cached list of available hash algorithms. + * * @var array|null */ private static ?array $algorithmsCache = null; + /** + * Cached result of SHA3-512 algorithm support check. + */ private static ?bool $isAlgorithmSupported = null; + /** + * Monotonic counter value for this CUID (prevents rapid-succession collisions). + */ private readonly int $counter; /** - * @var array + * Machine/process fingerprint as binary data (ensures uniqueness across machines). */ - private readonly array $fingerprint; + private readonly string $fingerprint; /** + * Configured length of the CUID string. + * * @var int<1, max> */ private readonly int $length; + /** + * Random lowercase letter prefix (a-z). + */ private readonly string $prefix; /** - * @var array + * Cryptographically secure random bytes. */ - private readonly array $random; + private readonly string $random; + /** + * Timestamp in milliseconds when this CUID was created. + */ private readonly int $timestamp; /** - * Initializes a new instance of Cuid2. + * The final rendered CUID string value (cached for performance). + */ + private readonly string $value; + + /** + * Initializes a new CUID2 instance. + * + * Generates all components (timestamp, counter, fingerprint, random data) and immediately + * renders the final CUID string for predictable performance and efficient repeated access. * - * @param int $maxLength The maximum string length value of the CUID. - * @throws OutOfRangeException The value of $maxLength was less than 4 or greater than 32. - * @throws Exception + * @param int $maxLength Total length of the CUID string (4-32 characters, default 24). + * + * @throws OutOfRangeException If $maxLength is less than 4 or greater than 32. + * @throws Exception If random byte generation fails (extremely rare). + * @throws BadParameterException If base conversion fails (should never occur). */ public function __construct(int $maxLength = 24) { if ($maxLength < 4 || $maxLength > 32) { - throw new OutOfRangeException("maxLength: cannot be less than 4 or greater than 32."); + throw new OutOfRangeException('maxLength: cannot be less than 4 or greater than 32.'); } + /** @phpstan-var int<4, 32> $maxLength */ $this->length = $maxLength; + $this->timestamp = self::generateTimestamp(); $this->counter = Counter::getInstance()->getNextValue(); - $this->fingerprint = Fingerprint::getInstance()->getValue(); + $this->random = self::generateRandom($maxLength); $this->prefix = chr(random_int(97, 122)); - $this->random = self::generateRandom(); - $this->timestamp = self::generateTimestamp(); + + // Generate value immediately for consistent performance characteristics + $this->value = $this->render(); } /** - * Generates a new CUID2. + * Static factory method to generate a new CUID2. + * + * Convenience method equivalent to `new Cuid2($maxLength)`. + * + * @param int $maxLength Total length of the CUID string (4-32 characters, default 24). + * + * @return Cuid2 A new CUID2 instance. * - * @param int $maxLength - * @return Cuid2 - * @throws Exception + * @throws OutOfRangeException If $maxLength is less than 4 or greater than 32. + * @throws Exception If random byte generation fails (extremely rare). + * @throws BadParameterException If base conversion fails (should never occur). */ public static function generate(int $maxLength = 24): Cuid2 { @@ -79,96 +145,151 @@ public static function generate(int $maxLength = 24): Cuid2 } /** - * Validates whether the given string is a valid CUID2 identifier. + * Validates whether a string conforms to the CUID2 format. * - * Function does not guarantee that the provided value is a CUID2 generated by this library, - * only that it conforms to the CUID2 format. + * Performs format validation only - checks length and character pattern. + * Does NOT verify the string was actually generated by this library. * - * @param string $id The CUID2 identifier to validate. - * @param int|null $expectedLength The expected length of the CUID2 identifier. - * If null, lengths of 4 to 32 characters are checked. + * Format requirements: + * - First character: lowercase letter (a-z) + * - Remaining characters: lowercase alphanumeric (a-z, 0-9) + * - Total length: 4-32 characters * - * @return bool True if the identifier is valid, false otherwise. + * @param string $id The string to validate. + * @param int|null $expectedLength Optional expected length for strict validation. + * If null, any length between 4-32 is accepted. + * + * @return bool True if the string matches CUID2 format, false otherwise. */ public static function isValid(string $id, ?int $expectedLength = null): bool { $length = strlen($id); - $isLengthValid = ($length >= 4 && $length <= 32) && - ($expectedLength === null || - ($expectedLength >= 4 && $expectedLength <= 32 && $length === $expectedLength)); + // Validate all length constraints in one check + if ( + $length < 4 || $length > 32 || + ($expectedLength !== null && ($expectedLength < 4 || $expectedLength > 32 || $length !== $expectedLength)) + ) { + return false; + } - if (!$isLengthValid) { + // Fast character-by-character validation + // First character must be lowercase letter + if ($id[0] < 'a' || $id[0] > 'z') { return false; } - $pattern = $expectedLength !== null - ? sprintf('/^[a-z][a-z0-9]{%d}$/', $expectedLength - 1) - : '/^[a-z][a-z0-9]{3,31}$/'; + // Remaining characters must be lowercase alphanumeric + $validChars = true; + for ($i = 1; $i < $length; $i++) { + $char = $id[$i]; + $isDigit = $char >= '0' && $char <= '9'; + $isLowerLetter = $char >= 'a' && $char <= 'z'; + + if (!$isDigit && !$isLowerLetter) { + $validChars = false; - return preg_match($pattern, $id) === 1; + break; + } + } + + return $validChars; } /** - * @throws Exception + * Returns the CUID string when the object is used in string context. + * + * @return string The cached CUID string value. */ public function __toString(): string { - return $this->render(); + return $this->value; } /** - * @return array - * @throws Exception + * Returns the CUID string representation. + * + * @return string The cached CUID string value. */ - private function generateRandom(): array + public function toString(): string { - $result = unpack('C*', random_bytes($this->length)); - return $result === false ? [] : $result; + return $this->value; } - private static function generateTimestamp(): int + /** + * Specifies data to be serialized to JSON. + * + * @return string The CUID string value for JSON encoding. + */ + #[Override] + public function jsonSerialize(): string { - return (int) (new DateTime())->format('Uv'); + return $this->value; } /** - * @throws Exception + * Generates cryptographically secure random bytes. + * + * Uses PHP's random_bytes() which provides CSPRNG (Cryptographically Secure + * Pseudo-Random Number Generator) for high-quality entropy. + * + * @param int<1, max> $length Number of random bytes to generate. + * + * @return string Binary string of random bytes. + * + * @throws Exception If an appropriate source of randomness cannot be found. */ - public function toString(): string + private static function generateRandom(int $length): string { - return $this->render(); + return random_bytes($length); } /** - * @inheritdoc - * @throws Exception + * Generates current timestamp in milliseconds. + * + * Uses hrtime() high-resolution monotonic timer for better performance and precision + * compared to DateTime object creation. The monotonic clock is not affected by system + * time adjustments. + * + * @return int Current timestamp in milliseconds since an arbitrary epoch. */ - #[Override] - public function jsonSerialize(): string + private static function generateTimestamp(): int { - return $this->render(); + return (int) (hrtime(as_number: true) / 1_000_000); } /** - * @throws Exception - * @throws BadParameterException + * Renders the CUID2 by hashing all components and converting to base36. + * + * Process: + * 1. Verifies SHA3-512 algorithm support + * 2. Initializes SHA3-512 hash context + * 3. Updates hash with timestamp, counter, random bytes, and fingerprint (binary data) + * 4. Finalizes hash to get base16 (hex) string + * 5. Converts base16 to base36 using GMP (preferred) or math-php fallback + * 6. Prepends random letter prefix and truncates to requested length + * + * @return string The final CUID2 identifier string. + * + * @throws InvalidOperationException If SHA3-512 algorithm is not supported. + * @throws BadParameterException If base conversion fails (should never occur). */ private function render(): string { self::$isAlgorithmSupported ??= self::isSupportedAlgorithm('sha3-512'); if (!self::$isAlgorithmSupported) { + // @codeCoverageIgnoreStart // phpcs:ignore Generic.Files.LineLength throw new InvalidOperationException('SHA3-512 appears to be unsupported - make sure you have support for it, or upgrade your version of PHP.'); + // @codeCoverageIgnoreEnd } $hash = hash_init('sha3-512'); - hash_update($hash, (string)$this->timestamp); - hash_update($hash, (string)$this->counter); - - hash_update($hash, bin2hex(pack('C*', ...$this->random))); - hash_update($hash, bin2hex(pack('C*', ...$this->fingerprint))); + hash_update($hash, (string) $this->timestamp); + hash_update($hash, (string) $this->counter); + hash_update($hash, $this->random); + hash_update($hash, $this->fingerprint); $hash = hash_final($hash); @@ -178,11 +299,19 @@ private function render(): string } /** - * Converts Base16 to Base36 + * Converts a base16 (hexadecimal) string to base36. + * + * Uses GMP extension if available for significantly better performance, + * otherwise falls back to math-php library for arbitrary precision arithmetic. * - * @param string $value - * @return string - * @throws BadParameterException + * Base36 encoding uses 0-9 and a-z (36 characters total), producing shorter + * strings than hexadecimal while remaining URL-safe and case-insensitive. + * + * @param string $value Base16 (hexadecimal) string to convert. + * + * @return string The value encoded in base36. + * + * @throws BadParameterException If base conversion fails (should never occur with valid input). */ private static function convert(string $value): string { @@ -191,18 +320,23 @@ private static function convert(string $value): string } $integer = BaseEncoderDecoder::createArbitraryInteger($value, 16); + return BaseEncoderDecoder::toBase($integer, 36, self::BASE36_ALPHANUMERIC); } /** - * Checks if the given algorithm is supported. + * Checks if a hash algorithm is supported by the current PHP installation. * - * @param string $algorithm the algorithm to check. - * @return bool true if the algorithm is supported, false otherwise. + * Results are cached in a static property to avoid repeated calls to hash_algos(). + * + * @param string $algorithm Hash algorithm name to check (e.g., 'sha3-512'). + * + * @return bool True if the algorithm is supported, false otherwise. */ private static function isSupportedAlgorithm(string $algorithm): bool { self::$algorithmsCache ??= hash_algos(); + return in_array($algorithm, self::$algorithmsCache, true); } } diff --git a/src/Fingerprint.php b/src/Fingerprint.php index c1a080d..bd5d86b 100644 --- a/src/Fingerprint.php +++ b/src/Fingerprint.php @@ -6,25 +6,90 @@ use Exception; +use const PHP_OS_FAMILY; + /** - * Singleton responsible for generating and storing a fingerprint + * Singleton responsible for generating and storing a unique machine/process fingerprint for CUID2 generation. + * + * This class ensures that CUIDs generated on different machines or in different processes are unique + * by creating a fingerprint that combines: + * - Hostname (machine identification) + * - Process ID (process identification) + * - Environment variables (additional entropy and context) + * - Random fallback (when hostname is unavailable) + * + * The fingerprint is computed once per process lifecycle and cached for performance. It is hashed + * using SHA3-512 to create a uniform, high-entropy identifier that becomes part of every CUID + * generated in this process. + * + * Thread Safety: + * - In PHP, each request/process maintains its own singleton instance + * - The singleton pattern ensures the fingerprint remains consistent within a single process + * - Different processes will have different fingerprints (by design) + * + * Singleton Protections: + * - Cannot be cloned (__clone is private) + * - Cannot be unserialized (__wakeup throws exception) + * - Cannot be directly instantiated (constructor is private) + * + * @internal This class is internal to the CUID2 library and should not be used directly. * - * @internal * @psalm-internal Visus\Cuid2 */ final class Fingerprint { + /** + * Maximum hostname length on Windows systems. + * + * Windows limits NetBIOS names to 15 characters. This constant ensures the random + * fallback identity matches the expected length constraints of the platform. + */ + private const WINDOWS_HOSTNAME_LENGTH = 15; + + /** + * Maximum hostname length on Unix-like systems. + * + * Unix-like systems (Linux, macOS, BSD) typically support hostnames up to 64 characters, + * but we use 32 characters to balance uniqueness with performance and storage efficiency. + */ + private const UNIX_HOSTNAME_LENGTH = 32; + + /** + * The singleton instance. + */ private static ?Fingerprint $instance = null; + /** + * Cached serialized environment variables. + * + * Environment variables are serialized once and cached to avoid repeated serialization + * overhead. This cache persists for the lifetime of the process. + */ private static ?string $cachedEnvironment = null; /** - * @var array + * The fingerprint value as binary string. + * + * Contains the raw bytes of the SHA3-512 hash that represents this machine/process + * fingerprint. Stored as a readonly string to ensure immutability after initialization. + * + * @psalm-readonly-allow-private-mutation */ - private readonly array $value; + private readonly string $value; /** - * @throws Exception + * Initializes the fingerprint by generating a unique machine/process identifier. + * + * The fingerprint combines multiple sources of entropy to ensure uniqueness: + * - Machine hostname (or random fallback if unavailable) + * - Process ID from the operating system + * - Serialized environment variables + * + * All components are hashed together using SHA3-512 to create a uniform, + * high-entropy fingerprint that helps ensure CUID uniqueness across different + * machines and processes. + * + * @throws Exception If SHA3-512 hashing is unavailable or fingerprint generation fails. */ private function __construct() { @@ -32,9 +97,52 @@ private function __construct() } /** - * Gets the current instance. + * Prevents cloning of the singleton instance. * - * @return Fingerprint + * Cloning would break the singleton pattern and could lead to inconsistent fingerprints, + * potentially causing CUID collisions across cloned instances. This method is intentionally + * private and empty to prevent cloning attempts. + * + * @codeCoverageIgnore + */ + private function __clone(): void + { + // Prevent cloning + } + + /** + * Prevents unserialization of the singleton instance. + * + * Unserializing would create a new instance with a potentially outdated fingerprint, + * breaking the singleton pattern and risking CUID collisions. This method throws an + * exception if unserialization is attempted. + * + * @throws InvalidOperationException Always thrown to prevent unserialization. + */ + public function __wakeup(): void + { + throw new InvalidOperationException('Cannot unserialize singleton'); + } + + /** + * Gets or creates the singleton Fingerprint instance. + * + * This method implements lazy initialization - the Fingerprint is only created when first + * accessed. Subsequent calls return the same instance, ensuring a consistent fingerprint + * throughout the process lifecycle. + * + * The fingerprint is computed once and cached, making this operation very efficient for + * repeated CUID generation within the same process. + * + * Usage: + * ```php + * $fingerprint = Fingerprint::getInstance(); + * $value = $fingerprint->getValue(); + * ``` + * + * @return Fingerprint The singleton Fingerprint instance. + * + * @throws Exception If SHA3-512 hashing is unavailable during first initialization. */ public static function getInstance(): Fingerprint { @@ -42,59 +150,88 @@ public static function getInstance(): Fingerprint } /** - * Gets the value from the instance. + * Returns the fingerprint value as a binary string. * - * @return array + * The fingerprint is represented as a binary string derived from the SHA3-512 hash + * of the combined identity components. This binary data is used as part of the CUID2 + * generation process to ensure uniqueness across machines and processes. + * + * Usage: + * ```php + * $fingerprint = Fingerprint::getInstance(); + * $bytes = $fingerprint->getValue(); // binary string + * ``` + * + * @return string Binary string representing the fingerprint. */ - public function getValue(): array + public function getValue(): string { return $this->value; } /** - * @return array - * @throws Exception + * Generates the machine/process fingerprint by combining multiple entropy sources. + * + * This method creates a unique identifier by hashing together: + * 1. Machine identity (hostname or random fallback) + * 2. Process ID (from the operating system) + * 3. Environment variables (serialized for additional context) + * + * The combined data is hashed using SHA3-512 to produce a uniform, high-entropy + * fingerprint returned as a binary string. + * + * Platform Considerations: + * - Windows: Uses 15-character identity (NetBIOS limit) + * - Unix-like: Uses 32-character identity (balance of uniqueness and performance) + * + * Fallback Behavior: + * If the hostname cannot be determined (containerized environments, restricted systems), + * a random identity string is generated as a fallback to maintain uniqueness. + * + * @return string Binary string from the SHA3-512 hash. + * + * @throws Exception If SHA3-512 hashing is unavailable or hash generation fails. */ - private function generateFingerprint(): array + private function generateFingerprint(): string { - $hostnameLength = PHP_OS_FAMILY === 'Windows' ? 15 : 32; + $identity = gethostname(); - $hostname = gethostname(); + // Fallback if native gethostname() returns false/empty (extremely rare) + // The compat.php polyfill already handles missing gethostname() function + // @codeCoverageIgnoreStart + if ($identity === false || $identity === '') { + $length = PHP_OS_FAMILY === 'Windows' + ? self::WINDOWS_HOSTNAME_LENGTH + : self::UNIX_HOSTNAME_LENGTH; - $identity = !empty($hostname) - ? $hostname - : $this->generateRandomIdentity($hostnameLength); + $identity = substr(str_shuffle('abcdefghjkmnpqrstvwxyz0123456789'), 0, $length); + } + // @codeCoverageIgnoreEnd $hash = hash_init('sha3-512'); hash_update($hash, $identity); - hash_update($hash, (string)getmypid()); + hash_update($hash, (string) getmypid()); hash_update($hash, $this->getCachedEnvironment()); - hash_update($hash, bin2hex(random_bytes(32))); - - $result = unpack('C*', hash_final($hash, true)); - - return $result !== false ? array_values($result) : []; - } - private function getCachedEnvironment(): string - { - return self::$cachedEnvironment ??= serialize(getenv()); + return hash_final($hash, true); } /** - * @codeCoverageIgnore + * Returns a cached serialized representation of environment variables. + * + * Environment variables provide additional entropy and context for the fingerprint. + * They are serialized once and cached to avoid repeated serialization overhead on + * every CUID generation. + * + * The serialized environment is used as part of the hash input to ensure that + * processes with different environment configurations generate different fingerprints, + * even if they share the same hostname and process ID pattern. + * + * @return string Serialized environment variables, cached for the process lifetime. */ - private function generateRandomIdentity(int $length): string + private function getCachedEnvironment(): string { - $chars = 'abcdefghjkmnpqrstvwxyz0123456789'; - $result = ''; - $max = strlen($chars) - 1; - - for ($i = 0; $i < $length; $i++) { - $result .= $chars[random_int(0, $max)]; - } - - return $result; + return self::$cachedEnvironment ??= serialize(getenv()); } } diff --git a/src/InvalidOperationException.php b/src/InvalidOperationException.php index 6e2f32c..ecc4ba0 100644 --- a/src/InvalidOperationException.php +++ b/src/InvalidOperationException.php @@ -1,12 +1,14 @@ getProperty('instance'); + $instance->setValue(null, null); + } + + /** + * @throws Exception + */ + public function testGetInstanceReturnsSameSingletonInstance(): void + { + $counter1 = Counter::getInstance(); + $counter2 = Counter::getInstance(); + + $this->assertSame($counter1, $counter2); + } + + /** + * @throws Exception + */ + public function testGetNextValueReturnsInteger(): void + { + $counter = Counter::getInstance(); + $value = $counter->getNextValue(); + + $this->assertGreaterThanOrEqual(0, $value); + } + + /** + * @throws Exception + */ + public function testGetNextValueIncrementsSequentially(): void + { + $counter = Counter::getInstance(); + + $value1 = $counter->getNextValue(); + $value2 = $counter->getNextValue(); + $value3 = $counter->getNextValue(); + + $this->assertEquals($value1 + 1, $value2); + $this->assertEquals($value2 + 1, $value3); + } + + /** + * @throws Exception + */ + public function testGetNextValueReturnsValueWithinRange(): void + { + $counter = Counter::getInstance(); + $reflection = new ReflectionClass(Counter::class); + $rangeConstant = $reflection->getConstant('RANGE'); + + for ($i = 0; $i < 100; $i++) { + $value = $counter->getNextValue(); + $this->assertGreaterThanOrEqual(0, $value); + $this->assertLessThan($rangeConstant, $value); + } + } + + /** + * @throws Exception + */ + public function testGetNextValueWrapsAtRange(): void + { + $counter = Counter::getInstance(); + $reflection = new ReflectionClass(Counter::class); + /** @var int $rangeConstant */ + $rangeConstant = $reflection->getConstant('RANGE'); + + // Use reflection to set the counter value near RANGE + $valueProperty = $reflection->getProperty('value'); + $valueProperty->setValue($counter, $rangeConstant - 2); + + $value1 = $counter->getNextValue(); + $value2 = $counter->getNextValue(); + $value3 = $counter->getNextValue(); + + $this->assertEquals($rangeConstant - 2, $value1); + $this->assertEquals($rangeConstant - 1, $value2); + $this->assertEquals(0, $value3); // Wrapped to 0 + } + + /** + * @throws Exception + */ + public function testWakeupThrowsException(): void + { + $counter = Counter::getInstance(); + + $this->expectException(InvalidOperationException::class); + $this->expectExceptionMessage('Cannot unserialize singleton'); + + $counter->__wakeup(); + } + + /** + * @throws Exception + */ + public function testInitialValueIsRandom(): void + { + // Create multiple instances (by resetting singleton) and verify they start with different values + $initialValues = []; + + for ($i = 0; $i < 10; $i++) { + $reflection = new ReflectionClass(Counter::class); + $instance = $reflection->getProperty('instance'); + $instance->setValue(null, null); + + $counter = Counter::getInstance(); + $initialValues[] = $counter->getNextValue(); + } + + // Statistical test: At least some values should be different + $uniqueValues = array_unique($initialValues); + $this->assertGreaterThan(1, count($uniqueValues)); + } + + /** + * @throws Exception + */ + public function testPersistsAcrossMultipleCalls(): void + { + $counter1 = Counter::getInstance(); + $value1 = $counter1->getNextValue(); + + $counter2 = Counter::getInstance(); + $value2 = $counter2->getNextValue(); + + // Should be the same instance, so value2 should be value1 + 1 + $this->assertEquals($value1 + 1, $value2); + } +} diff --git a/tests/Cuid2Test.php b/tests/Cuid2Test.php index da0d4ff..9c15694 100644 --- a/tests/Cuid2Test.php +++ b/tests/Cuid2Test.php @@ -84,62 +84,45 @@ public static function invalidCuidProvider(): array } /** - * Tests that the generated CUID2 contains only valid base36 characters. - * * @throws OutOfRangeException|Exception */ - public function testContainsOnlyBase36Characters(): void + public function testGeneratesValidBase36Format(): void { $cuid = new Cuid2(); - $result = (string)$cuid; + $result = (string) $cuid; $this->assertMatchesRegularExpression( - '/^[0-9a-z]+$/', - $result, - 'CUID should only contain base36 characters (0-9, a-z)' - ); - - $this->assertDoesNotMatchRegularExpression( - '/[A-Z]/', - $result, - 'CUID should not contain uppercase letters' - ); - - $this->assertDoesNotMatchRegularExpression( - '/[^0-9a-z]/', + '/^[a-z][0-9a-z]+$/', $result, - 'CUID should not contain special characters or spaces' + 'CUID should start with lowercase letter followed by base36 characters' ); } /** - * Tests that the string representation of CUID2 is consistent across all methods. - * * @throws OutOfRangeException|Exception */ - public function testStringRepresentationConsistency(): void + public function testStringRepresentationsAreConsistent(): void { $cuid = new Cuid2(); $toString = $cuid->toString(); - $magicToString = (string)$cuid; + $magicToString = (string) $cuid; $jsonSerialize = $cuid->jsonSerialize(); - $this->assertSame($toString, $magicToString, 'toString() and __toString() should return identical values'); - $this->assertSame($toString, $jsonSerialize, 'toString() and jsonSerialize() should return identical values'); + $this->assertSame($toString, $magicToString); + $this->assertSame($toString, $jsonSerialize); // Test immutability - multiple calls return same value - $this->assertSame($toString, $cuid->toString(), 'Multiple calls to toString() should return same value'); - $this->assertSame($magicToString, (string)$cuid, 'Multiple casts to string should return same value'); + $this->assertSame($toString, $cuid->toString()); + $this->assertSame($magicToString, (string) $cuid); } /** - * Tests that invalid lengths throw appropriate exceptions. + * @throws Exception * * @dataProvider invalidLengthProvider - * @throws Exception */ - public function testInvalidLengthThrowsException(int $length): void + public function testThrowsExceptionForInvalidLength(int $length): void { $this->expectException(OutOfRangeException::class); $this->expectExceptionMessage('maxLength: cannot be less than 4 or greater than 32.'); @@ -148,325 +131,119 @@ public function testInvalidLengthThrowsException(int $length): void } /** - * Tests the default constructor produces correct format. - * * @throws OutOfRangeException|Exception */ - public function testDefaultConstructor(): void + public function testGeneratesDefaultLengthOf24(): void { $cuid = new Cuid2(); - $result = (string)$cuid; + $result = (string) $cuid; - $this->assertEquals(24, strlen($result), 'Default CUID should be 24 characters long'); - $this->assertTrue(ctype_alnum($result), 'Default CUID should be alphanumeric'); - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $result, - 'CUID should start with lowercase letter' - ); + $this->assertEquals(24, strlen($result)); + $this->assertMatchesRegularExpression('/^[a-z][0-9a-z]*$/', $result); } /** - * Tests that different instances generate unique values. - * * @throws OutOfRangeException|Exception */ - public function testUniquenessAcrossInstances(): void + public function testGeneratesUniqueValuesAcrossInstances(): void { $cuid1 = new Cuid2(); $cuid2 = new Cuid2(); - $this->assertNotEquals( - (string)$cuid1, - (string)$cuid2, - 'Different CUID instances should generate unique values' - ); - } - - /** - * Tests explicit toString method. - * - * @throws OutOfRangeException|Exception - */ - public function testExplicitToString(): void - { - $cuid = new Cuid2(); - $value = $cuid->toString(); - - $this->assertEquals(24, strlen($value), 'toString() should return 24 character string'); - $this->assertTrue(ctype_alnum($value), 'toString() result should be alphanumeric'); - $this->assertMatchesRegularExpression( - '/^[a-z]/', - $value, - 'toString() result should start with lowercase letter' - ); - } - - /** - * Tests implicit string conversion. - * - * @throws OutOfRangeException|Exception - */ - public function testImplicitStringConversion(): void - { - $cuid = new Cuid2(); - - $castValue = (string)$cuid; - $this->assertEquals(24, strlen($castValue), 'Cast to string should return 24 character string'); - $this->assertTrue(ctype_alnum($castValue), 'Cast to string result should be alphanumeric'); - - ob_start(); - echo $cuid; - $echoValue = ob_get_contents(); - ob_end_clean(); - - $echoValue = !empty($echoValue) ? $echoValue : ''; - - $this->assertEquals(24, strlen($echoValue), 'Echo output should be 24 characters long'); - $this->assertTrue(ctype_alnum($echoValue), 'Echo output should be alphanumeric'); - $this->assertEquals($castValue, $echoValue, 'Cast and echo should produce same result'); + $this->assertNotEquals((string) $cuid1, (string) $cuid2); } /** - * Tests JSON encoding integration. - * * @throws OutOfRangeException|Exception */ - public function testJsonEncodingIntegration(): void + public function testJsonEncodesCorrectly(): void { $cuid = new Cuid2(); $jsonString = json_encode($cuid); - - $this->assertIsString($jsonString, 'json_encode should return string'); - $this->assertStringStartsWith('"', $jsonString, 'JSON string should start with quote'); - $this->assertStringEndsWith('"', $jsonString, 'JSON string should end with quote'); + $this->assertIsString($jsonString); $decoded = json_decode($jsonString, true); - $this->assertIsString($decoded, 'Decoded JSON should be string'); - $this->assertEquals(24, strlen($decoded), 'Decoded CUID should be 24 characters'); - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $decoded, - 'Decoded CUID should have correct format' - ); - } - - /** - * Tests JSON serialization method. - * - * @throws OutOfRangeException|Exception - */ - public function testJsonSerialize(): void - { - $cuid = new Cuid2(); - $jsonValue = $cuid->jsonSerialize(); - - $this->assertEquals(24, strlen($jsonValue), 'JSON serialized value should be 24 characters'); - $this->assertTrue(ctype_alnum($jsonValue), 'JSON serialized value should be alphanumeric'); - $this->assertMatchesRegularExpression( - '/^[a-z]/', - $jsonValue, - 'JSON serialized value should start with lowercase letter' - ); - } - - /** - * Tests length consistency across different constructor parameters. - * - * @throws OutOfRangeException|Exception - */ - public function testLengthConsistencyWithDifferentLengths(): void - { - $lengths = [4, 8, 12, 16, 20, 24, 28, 32]; - - foreach ($lengths as $length) { - $cuid1 = new Cuid2($length); - $cuid2 = new Cuid2($length); - - $result1 = (string)$cuid1; - $result2 = (string)$cuid2; - - $this->assertEquals($length, strlen($result1), "CUID with length $length should have correct length"); - $this->assertEquals($length, strlen($result2), "CUID with length $length should have correct length"); - $this->assertNotEquals($result1, $result2, 'Different instances with same length should be unique'); - - // Verify format for each length - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $result1, - "CUID with length $length should have correct format" - ); - - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $result2, - "CUID with length $length should have correct format" - ); - } + $this->assertIsString($decoded); + $this->assertEquals((string) $cuid, $decoded); + $this->assertMatchesRegularExpression('/^[a-z][0-9a-z]*$/', $decoded); } /** - * Tests that the prefix is always a lowercase letter. - * * @throws OutOfRangeException|Exception */ - public function testPrefixIsAlwaysLowercaseLetter(): void + public function testStartsWithLowercaseLetter(): void { - // Test multiple instances to verify consistency for ($i = 0; $i < 50; $i++) { $cuid = new Cuid2(); - $result = (string)$cuid; + $result = (string) $cuid; $firstChar = $result[0]; - $this->assertTrue(ctype_alpha($firstChar), 'First character should be alphabetic'); - $this->assertTrue(ctype_lower($firstChar), 'First character should be lowercase'); - $this->assertGreaterThanOrEqual('a', $firstChar, 'First character should be >= "a"'); - $this->assertLessThanOrEqual('z', $firstChar, 'First character should be <= "z"'); + $this->assertMatchesRegularExpression('/^[a-z]$/', $firstChar); } } /** - * Tests uniqueness of generated CUIDs with larger sample size. - * * @throws OutOfRangeException|Exception */ - public function testUniquenessWithLargeSample(): void + public function testGeneratesUniqueValuesInLargeSample(): void { $cuids = []; $sampleSize = 1000; for ($i = 0; $i < $sampleSize; $i++) { - $cuids[] = (string)new Cuid2(); + $cuids[] = (string) new Cuid2(); } $uniqueCuids = array_unique($cuids); - $this->assertCount($sampleSize, $uniqueCuids, "All $sampleSize generated CUIDs should be unique"); - - // Verify each CUID has correct format - foreach ($cuids as $index => $cuid) { - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $cuid, - "CUID at index $index should have correct format" - ); - } + $this->assertCount($sampleSize, $uniqueCuids); } /** - * @dataProvider validLengthProvider * @throws Exception - */ - public function testValidLengthsProduceCorrectFormat(int $length): void - { - $cuid = new Cuid2($length); - $result = (string)$cuid; - - $this->assertEquals($length, strlen($result), "CUID should have requested length of $length"); - $this->assertTrue(ctype_alnum($result), 'CUID should be alphanumeric'); - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $result, - 'CUID should start with lowercase letter and contain only base36 characters' - ); - } - - /** - * Tests variable length constructor with specific length. * - * @throws OutOfRangeException|Exception + * @dataProvider validLengthProvider */ - public function testVariableLengthConstructor(): void + public function testGeneratesCorrectLength(int $length): void { - $length = 10; $cuid = new Cuid2($length); - $result = (string)$cuid; + $result = (string) $cuid; - $this->assertEquals($length, strlen($result), "CUID should have requested length of $length"); - $this->assertTrue(ctype_alnum($result), 'CUID should be alphanumeric'); - $this->assertMatchesRegularExpression( - '/^[a-z]/', - $result, - 'CUID should start with lowercase letter' - ); - } - - /** - * Tests that CUIDs maintain format consistency across different lengths. - * - * @throws OutOfRangeException|Exception - */ - public function testFormatConsistencyAcrossLengths(): void - { - $lengths = [4, 8, 16, 24, 32]; - - foreach ($lengths as $length) { - $cuid = new Cuid2($length); - $result = (string)$cuid; - - // All CUIDs should follow the same format rules regardless of length - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $result, - "CUID with length $length should follow format rules" - ); - - $this->assertEquals($length, strlen($result), "CUID should have exact length $length"); - - // Verify no invalid characters - $this->assertDoesNotMatchRegularExpression( - '/[^0-9a-z]/', - $result, - 'CUID should not contain invalid characters' - ); - } + $this->assertEquals($length, strlen($result)); + $this->assertMatchesRegularExpression('/^[a-z][0-9a-z]*$/', $result); } /** - * Tests the static generate method. - * * @throws OutOfRangeException|Exception */ - public function testStaticGenerateMethod(): void + public function testStaticGenerateCreatesDefaultLength(): void { $cuid = Cuid2::generate(); - $result = (string)$cuid; + $result = (string) $cuid; - $this->assertEquals(24, strlen($result), 'Generated CUID should be 24 characters long'); - $this->assertTrue(ctype_alnum($result), 'Generated CUID should be alphanumeric'); - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $result, - 'Generated CUID should start with lowercase letter' - ); + $this->assertEquals(24, strlen($result)); + $this->assertMatchesRegularExpression('/^[a-z][0-9a-z]*$/', $result); } /** - * Tests the static generate method with custom length. + * @throws Exception * * @dataProvider validLengthProvider - * @throws Exception */ - public function testStaticGenerateMethodWithLength(int $length): void + public function testStaticGenerateCreatesCustomLength(int $length): void { $cuid = Cuid2::generate($length); - $result = (string)$cuid; + $result = (string) $cuid; - $this->assertEquals($length, strlen($result), "Generated CUID should have requested length of $length"); - $this->assertTrue(ctype_alnum($result), 'Generated CUID should be alphanumeric'); - $this->assertMatchesRegularExpression( - '/^[a-z][0-9a-z]*$/', - $result, - 'Generated CUID should start with lowercase letter and contain only base36 characters' - ); + $this->assertEquals($length, strlen($result)); + $this->assertMatchesRegularExpression('/^[a-z][0-9a-z]*$/', $result); } /** - * Tests that static generate method throws exception for invalid lengths. + * @throws Exception * * @dataProvider invalidLengthProvider - * @throws Exception */ - public function testStaticGenerateMethodThrowsExceptionForInvalidLength(int $length): void + public function testStaticGenerateThrowsExceptionForInvalidLength(int $length): void { $this->expectException(OutOfRangeException::class); $this->expectExceptionMessage('maxLength: cannot be less than 4 or greater than 32.'); @@ -475,225 +252,80 @@ public function testStaticGenerateMethodThrowsExceptionForInvalidLength(int $len } /** - * Tests that static generate method produces unique values. - * * @throws OutOfRangeException|Exception */ - public function testStaticGenerateMethodUniqueness(): void + public function testStaticGenerateProducesUniqueValues(): void { $cuid1 = Cuid2::generate(); $cuid2 = Cuid2::generate(); - $this->assertNotEquals( - (string)$cuid1, - (string)$cuid2, - 'Different calls to generate() should produce unique values' - ); + $this->assertNotEquals((string) $cuid1, (string) $cuid2); } /** - * Tests equivalence between constructor and static generate method. - * - * @throws OutOfRangeException|Exception - */ - public function testConstructorAndGenerateMethodEquivalence(): void - { - $length = 16; - - // Both methods should produce CUIDs with identical characteristics - $constructorCuid = new Cuid2($length); - $generateCuid = Cuid2::generate($length); - - $constructorResult = (string)$constructorCuid; - $generateResult = (string)$generateCuid; - - // Should have same length and format, but different values - $this->assertEquals(strlen($constructorResult), - strlen($generateResult), - 'Both methods should produce same length' - ); - - $this->assertMatchesRegularExpression('/^[a-z][0-9a-z]*$/', - $constructorResult, - 'Constructor result should have correct format' - ); - - $this->assertMatchesRegularExpression('/^[a-z][0-9a-z]*$/', - $generateResult, - 'Generate result should have correct format' - ); - - $this->assertNotEquals($constructorResult, $generateResult, 'Results should be unique'); - } - - /** - * Tests isValid method with valid CUID2 strings. - * * @dataProvider validCuidProvider */ - public function testIsValidWithValidCuids(string $cuid, ?int $expectedLength = null): void + public function testIsValidAcceptsValidCuids(string $cuid, ?int $expectedLength = null): void { - $this->assertTrue( - Cuid2::isValid($cuid, $expectedLength), - "CUID '$cuid' should be considered valid" - ); + $this->assertTrue(Cuid2::isValid($cuid, $expectedLength)); } /** - * Tests isValid method with invalid CUID2 strings. - * * @dataProvider invalidCuidProvider */ - public function testIsValidWithInvalidCuids(string $cuid, ?int $expectedLength = null): void + public function testIsValidRejectsInvalidCuids(string $cuid, ?int $expectedLength = null): void { - $this->assertFalse( - Cuid2::isValid($cuid, $expectedLength), - "CUID '$cuid' should be considered invalid" - ); + $this->assertFalse(Cuid2::isValid($cuid, $expectedLength)); } - /** - * Tests isValid method with length validation. - */ - public function testIsValidWithExpectedLength(): void + public function testIsValidChecksExpectedLength(): void { $validCuid = 'a1b2c3d4e5f6g7h8'; - // Should be valid when length matches - $this->assertTrue( - Cuid2::isValid($validCuid, 16), - 'Valid CUID should pass when expected length matches actual length' - ); - - // Should be invalid when length doesn't match - $this->assertFalse( - Cuid2::isValid($validCuid, 24), - 'Valid CUID should fail when expected length differs from actual length' - ); - - $this->assertFalse( - Cuid2::isValid($validCuid, 8), - 'Valid CUID should fail when expected length is shorter than actual length' - ); + $this->assertTrue(Cuid2::isValid($validCuid, 16)); + $this->assertFalse(Cuid2::isValid($validCuid, 24)); + $this->assertFalse(Cuid2::isValid($validCuid, 8)); } - /** - * Tests isValid method with edge cases for length validation. - */ - public function testIsValidLengthEdgeCases(): void + public function testIsValidChecksLengthBounds(): void { - // Test minimum valid length - $this->assertTrue(Cuid2::isValid('a1b2', 4), 'Minimum length CUID should be valid'); - $this->assertFalse(Cuid2::isValid('a1b', 3), 'Below minimum length should be invalid even with matching expected length'); + $this->assertTrue(Cuid2::isValid('a1b2', 4)); + $this->assertFalse(Cuid2::isValid('a1b', 3)); - // Test maximum valid length $maxLengthCuid = 'a' . str_repeat('1', 31); - $this->assertTrue(Cuid2::isValid($maxLengthCuid, 32), 'Maximum length CUID should be valid'); + $this->assertTrue(Cuid2::isValid($maxLengthCuid, 32)); - // Test above maximum length $tooLongCuid = 'a' . str_repeat('1', 32); - $this->assertFalse(Cuid2::isValid($tooLongCuid, 33), 'Above maximum length should be invalid even with matching expected length'); + $this->assertFalse(Cuid2::isValid($tooLongCuid, 33)); } - /** - * Tests isValid method without expected length parameter. - */ - public function testIsValidWithoutExpectedLength(): void + public function testIsValidRejectsInvalidExpectedLength(): void { - $this->assertTrue(Cuid2::isValid('a1b2'), 'Valid minimum length CUID should pass without expected length'); - $this->assertTrue(Cuid2::isValid('a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6'), 'Valid maximum length CUID should pass without expected length'); - $this->assertFalse(Cuid2::isValid('abc'), 'Too short CUID should fail without expected length'); - $this->assertFalse(Cuid2::isValid('A1b2'), 'CUID with uppercase should fail without expected length'); + // Valid CUID but invalid expectedLength parameter + $validCuid = 'a1b2c3d4'; + + $this->assertFalse(Cuid2::isValid($validCuid, 3)); // expectedLength too small + $this->assertFalse(Cuid2::isValid($validCuid, 33)); // expectedLength too large + $this->assertFalse(Cuid2::isValid($validCuid, 0)); // expectedLength zero + $this->assertFalse(Cuid2::isValid($validCuid, -1)); // expectedLength negative } /** - * Tests isValid method with generated CUIDs. - * * @throws Exception */ - public function testIsValidWithGeneratedCuids(): void + public function testIsValidAcceptsGeneratedCuids(): void { $lengths = [4, 8, 16, 24, 32]; foreach ($lengths as $length) { $cuid = Cuid2::generate($length); - $cuidString = (string)$cuid; + $cuidString = (string) $cuid; - // Generated CUID should always be valid - $this->assertTrue( - Cuid2::isValid($cuidString), - "Generated CUID of length $length should be valid" - ); + $this->assertTrue(Cuid2::isValid($cuidString)); + $this->assertTrue(Cuid2::isValid($cuidString, $length)); - // Generated CUID should be valid with correct expected length - $this->assertTrue( - Cuid2::isValid($cuidString, $length), - "Generated CUID should be valid with matching expected length $length" - ); - - // Generated CUID should be invalid with wrong expected length $wrongLength = $length === 4 ? 8 : 4; - $this->assertFalse( - Cuid2::isValid($cuidString, $wrongLength), - "Generated CUID should be invalid with wrong expected length $wrongLength" - ); - } - } - - /** - * Tests isValid method with character set validation. - */ - public function testIsValidCharacterSetValidation(): void - { - // Test all valid base36 characters - $validChars = '0123456789abcdefghijklmnopqrstuvwxyz'; - $testCuid = 'a' . substr(str_shuffle($validChars), 0, 7); - $this->assertTrue(Cuid2::isValid($testCuid), 'CUID with all valid base36 characters should be valid'); - - // Test invalid characters - $invalidChars = ['A', 'Z', '-', '_', '@', '#', '$', '%', '^', '&', '*']; - foreach ($invalidChars as $invalidChar) { - $invalidCuid = 'a1b2' . $invalidChar . '3d4'; - $this->assertFalse( - Cuid2::isValid($invalidCuid), - "CUID containing invalid character '$invalidChar' should be invalid" - ); - } - } - - /** - * Tests isValid method regex pattern matching. - */ - public function testIsValidRegexPattern(): void - { - // Test the regex pattern directly through various scenarios - $validPatterns = [ - 'a123', - 'z999', - 'x1y2z3a4b5c6', - 'q0w1e2r3t4y5u6i7o8p9', - ]; - - foreach ($validPatterns as $pattern) { - $this->assertTrue( - Cuid2::isValid($pattern), - "Pattern '$pattern' should match valid CUID regex" - ); - } - - $invalidPatterns = [ - 'A123', // uppercase - 'a-23', // contains hyphen - 'a_23', // contains underscore - 'a 23', // contains space - 'a.23', // contains dot - ]; - - foreach ($invalidPatterns as $pattern) { - $this->assertFalse( - Cuid2::isValid($pattern), - "Pattern '$pattern' should not match valid CUID regex" - ); + $this->assertFalse(Cuid2::isValid($cuidString, $wrongLength)); } } } diff --git a/tests/FingerprintTest.php b/tests/FingerprintTest.php new file mode 100644 index 0000000..0a04012 --- /dev/null +++ b/tests/FingerprintTest.php @@ -0,0 +1,139 @@ +getProperty('instance'); + $instance->setValue(null, null); + + $cachedEnvironment = $reflection->getProperty('cachedEnvironment'); + $cachedEnvironment->setValue(null, null); + } + + /** + * @throws Exception + */ + public function testGetInstanceReturnsSameSingletonInstance(): void + { + $fingerprint1 = Fingerprint::getInstance(); + $fingerprint2 = Fingerprint::getInstance(); + + $this->assertSame($fingerprint1, $fingerprint2); + } + + /** + * @throws Exception + */ + public function testGetValueReturnsNonEmptyString(): void + { + $fingerprint = Fingerprint::getInstance(); + $value = $fingerprint->getValue(); + + $this->assertNotEmpty($value); + } + + /** + * @throws Exception + */ + public function testGetValueReturnsConsistentValue(): void + { + $fingerprint = Fingerprint::getInstance(); + + $value1 = $fingerprint->getValue(); + $value2 = $fingerprint->getValue(); + $value3 = $fingerprint->getValue(); + + $this->assertSame($value1, $value2); + $this->assertSame($value2, $value3); + } + + /** + * @throws Exception + */ + public function testGetValueReturnsBinaryData(): void + { + $fingerprint = Fingerprint::getInstance(); + $value = $fingerprint->getValue(); + + // SHA3-512 produces 64 bytes of binary data + $this->assertEquals(64, strlen($value)); + } + + /** + * @throws Exception + */ + public function testGetValueIsDeterministicWithinProcess(): void + { + // Within the same process, fingerprint should be identical across instances + $fingerprint1 = Fingerprint::getInstance(); + $value1 = $fingerprint1->getValue(); + + $fingerprint2 = Fingerprint::getInstance(); + $value2 = $fingerprint2->getValue(); + + $this->assertSame($value1, $value2); + $this->assertSame($fingerprint1, $fingerprint2); + } + + /** + * @throws Exception + */ + public function testWakeupThrowsException(): void + { + $fingerprint = Fingerprint::getInstance(); + + $this->expectException(InvalidOperationException::class); + $this->expectExceptionMessage('Cannot unserialize singleton'); + + $fingerprint->__wakeup(); + } + + /** + * @throws Exception + */ + public function testFingerprintIncludesProcessContext(): void + { + // Create a fingerprint and verify it's unique (non-zero bytes) + $fingerprint = Fingerprint::getInstance(); + $value = $fingerprint->getValue(); + + // Binary data should not be all zeros (extremely unlikely with SHA3-512) + $this->assertNotEquals(str_repeat("\x00", 64), $value); + + // Should contain various byte values (high entropy) + $uniqueBytes = count(array_unique(str_split($value))); + $this->assertGreaterThan(10, $uniqueBytes); + } + + /** + * @throws Exception + */ + public function testFingerprintValueIsImmutable(): void + { + $fingerprint = Fingerprint::getInstance(); + $originalValue = $fingerprint->getValue(); + + // Call getValue multiple times + for ($i = 0; $i < 10; $i++) { + $currentValue = $fingerprint->getValue(); + $this->assertSame($originalValue, $currentValue); + } + } +} diff --git a/tests/benchmark/Cuid2Bench.php b/tests/benchmark/Cuid2Bench.php new file mode 100644 index 0000000..280abdd --- /dev/null +++ b/tests/benchmark/Cuid2Bench.php @@ -0,0 +1,163 @@ +cuid; + } + + /** + * Benchmark toString() method performance. + */ + #[BeforeMethods('setUp')] + #[Revs(10000)] + #[Iterations(10)] + #[Warmup(2)] + #[Groups(['conversion', 'string'])] + public function benchToStringMethod(): void + { + // @phpcs:ignore SlevomatCodingStandard.Variables.UnusedVariable.UnusedVariable + $result = $this->cuid->toString(); + } + + /** + * Benchmark JSON serialization performance. + */ + #[BeforeMethods('setUp')] + #[Revs(10000)] + #[Iterations(10)] + #[Warmup(2)] + #[Groups(['conversion', 'json'])] + public function benchJsonSerialize(): void + { + json_encode($this->cuid); + } + + /** + * Benchmark batch generation of CUIDs. + * + * Tests performance when generating multiple CUIDs in sequence. + * + * @param array{count: int} $params + */ + #[ParamProviders('provideBatchSizes')] + #[Revs(100)] + #[Iterations(10)] + #[Warmup(2)] + #[Groups(['generation', 'batch'])] + public function benchBatchGeneration(array $params): void + { + for ($i = 0; $i < $params['count']; $i++) { + new Cuid2(); + } + } + + /** + * Provides various CUID lengths for benchmarking. + * + * @return iterable + */ + public function provideLengths(): iterable + { + yield 'minimum-4' => ['length' => 4]; + yield 'short-10' => ['length' => 10]; + yield 'default-24' => ['length' => 24]; + yield 'maximum-32' => ['length' => 32]; + } + + /** + * Provides batch sizes for batch generation benchmarks. + * + * @return iterable + */ + public function provideBatchSizes(): iterable + { + yield 'small-10' => ['count' => 10]; + yield 'medium-100' => ['count' => 100]; + yield 'large-1000' => ['count' => 1000]; + } + + /** + * CUID instance for conversion benchmarks. + */ + private Cuid2 $cuid; + + /** + * Set up CUID instance for conversion benchmarks. + */ + public function setUp(): void + { + $this->cuid = new Cuid2(); + } +} diff --git a/tests/benchmark/SingletonBench.php b/tests/benchmark/SingletonBench.php new file mode 100644 index 0000000..ac6f3ef --- /dev/null +++ b/tests/benchmark/SingletonBench.php @@ -0,0 +1,101 @@ +getNextValue(); + } + + /** + * Benchmark Fingerprint singleton getInstance() access. + * + * Tests the performance of accessing an already-initialized Fingerprint singleton. + * After the first access, this should be extremely fast due to caching. + */ + #[Revs(100000)] + #[Iterations(10)] + #[Warmup(2)] + #[Groups(['singleton', 'fingerprint'])] + public function benchFingerprintGetInstance(): void + { + Fingerprint::getInstance(); + } + + /** + * Benchmark Fingerprint getValue() performance. + * + * Tests the performance of retrieving the cached fingerprint value. + * This should be extremely fast as it simply returns a readonly property. + */ + #[Revs(100000)] + #[Iterations(10)] + #[Warmup(2)] + #[Groups(['singleton', 'fingerprint'])] + public function benchFingerprintGetValue(): void + { + // @phpcs:ignore SlevomatCodingStandard.Variables.UnusedVariable.UnusedVariable + $result = Fingerprint::getInstance()->getValue(); + } + + /** + * Benchmark combined singleton access for CUID generation. + * + * This simulates the singleton access pattern used during CUID generation, + * where both Counter and Fingerprint are accessed. + */ + #[Revs(10000)] + #[Iterations(10)] + #[Warmup(2)] + #[Groups(['singleton', 'combined'])] + public function benchCombinedSingletonAccess(): void + { + // @phpcs:ignore SlevomatCodingStandard.Variables.UnusedVariable.UnusedVariable + $counterValue = Counter::getInstance()->getNextValue(); + // @phpcs:ignore SlevomatCodingStandard.Variables.UnusedVariable.UnusedVariable + $fingerprintValue = Fingerprint::getInstance()->getValue(); + } +} diff --git a/tests/benchmark/ValidationBench.php b/tests/benchmark/ValidationBench.php new file mode 100644 index 0000000..98915f6 --- /dev/null +++ b/tests/benchmark/ValidationBench.php @@ -0,0 +1,149 @@ +longString); + } + + /** + * Provides valid CUIDs of various lengths. + * + * @return iterable + */ + public function provideValidCuids(): iterable + { + yield 'minimum-4' => ['cuid' => (new Cuid2(4))->toString()]; + yield 'short-10' => ['cuid' => (new Cuid2(10))->toString()]; + yield 'default-24' => ['cuid' => (new Cuid2())->toString()]; + yield 'maximum-32' => ['cuid' => (new Cuid2(32))->toString()]; + } + + /** + * Provides valid CUIDs with their expected lengths. + * + * @return iterable + */ + public function provideValidCuidsWithLength(): iterable + { + yield 'minimum-4' => ['cuid' => (new Cuid2(4))->toString(), 'length' => 4]; + yield 'short-10' => ['cuid' => (new Cuid2(10))->toString(), 'length' => 10]; + yield 'default-24' => ['cuid' => (new Cuid2())->toString(), 'length' => 24]; + yield 'maximum-32' => ['cuid' => (new Cuid2(32))->toString(), 'length' => 32]; + } + + /** + * Provides invalid CUID strings. + * + * @return iterable + */ + public function provideInvalidCuids(): iterable + { + yield 'uppercase-first' => ['cuid' => 'A23456789012345678901234']; + yield 'uppercase-middle' => ['cuid' => 'a234567890123456789O1234']; + yield 'contains-dash' => ['cuid' => 'a234567890-234567890123']; + yield 'contains-underscore' => ['cuid' => 'a2345678_01234567890123']; + yield 'contains-special' => ['cuid' => 'a23456789@1234567890123']; + yield 'starts-with-number' => ['cuid' => '123456789012345678901234']; + yield 'too-short' => ['cuid' => 'abc']; + } + + /** + * Long invalid string for edge case testing. + */ + private string $longString; + + /** + * Set up long string for validation benchmark. + */ + public function setUpLongString(): void + { + $this->longString = str_repeat('a', 100); + } +}