diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9559213 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.{json,xml,yaml,yml}] +indent_size = 2 diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000..bad2d4b --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,35 @@ +name: PHPStan + +on: + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + phpstan: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Composer Cache + uses: actions/cache@v4 + with: + path: /tmp/composer-cache + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + - uses: php-actions/composer@v6 + - name: Gather PHP Paths + id: gather-php-paths + run: | + # Gather all the directories that contain PHP files and all the root level php files, too. + { + printf 'paths=' + git ls-files '*.php' | awk -v ORS=' ' -F / '!$2 { print; next; } !s[$1]++ { print $1 }' + } >> "$GITHUB_OUTPUT" + - uses: php-actions/phpstan@v3 + with: + path: ${{ steps.gather-php-paths.outputs.paths }} diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..ded092d --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,23 @@ +name: PHPUnit + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Composer Cache + uses: actions/cache@v4 + with: + path: /tmp/composer-cache + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + - uses: php-actions/composer@v6 + - uses: php-actions/phpunit@v3 diff --git a/.gitignore b/.gitignore index 57872d0..46113e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /vendor/ +.phpunit.result.cache diff --git a/composer.json b/composer.json index 1cb5979..ff3857a 100644 --- a/composer.json +++ b/composer.json @@ -13,5 +13,9 @@ "email": "michael@opencoreemr.com" } ], - "require": {} + "require-dev": { + "phpstan/phpstan": "^2.1", + "rector/rector": "^2.0", + "phpunit/phpunit": "^12.2" + } } diff --git a/composer.lock b/composer.lock index 27d5002..feaaae8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,1741 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2205a45b8768d81d252210f986eecde3", + "content-hash": "fb1ba9edb5307dbeb3d24a407e9baab5", "packages": [], - "packages-dev": [], + "packages-dev": [ + { + "name": "myclabs/deep-copy", + "version": "1.13.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", + "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.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-04-29T12:36:36+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.5.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "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.0-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.5.0" + }, + "time": "2025-05-31T08:24:38+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": "phpstan/phpstan", + "version": "2.1.17", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-05-21T20:55:28+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "12.3.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ddec29dfc128eba9c204389960f2063f3b7fa170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ddec29dfc128eba9c204389960f2063f3b7fa170", + "reference": "ddec29dfc128eba9c204389960f2063f3b7fa170", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.3", + "phpunit/php-file-iterator": "^6.0", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.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": "12.3.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/12.3.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/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-06-18T08:58:13+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.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": "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/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:37+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "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": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:58+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "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/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:16+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:38+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "12.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "19e25c2da3f8071a683ee1e445b0e24bba25de61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/19e25c2da3f8071a683ee1e445b0e24bba25de61", + "reference": "19e25c2da3f8071a683ee1e445b0e24bba25de61", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.3.0", + "phpunit/php-file-iterator": "^6.0.0", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.0.0", + "sebastian/comparator": "^7.0.1", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.0.2", + "sebastian/exporter": "^7.0.0", + "sebastian/global-state": "^8.0.0", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/type": "^6.0.2", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.2-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/12.2.2" + }, + "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-06-13T05:49:28+00:00" + }, + { + "name": "rector/rector", + "version": "2.0.18", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "be3a452085b524a04056e3dfe72d861948711062" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/be3a452085b524a04056e3dfe72d861948711062", + "reference": "be3a452085b524a04056e3dfe72d861948711062", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.17" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/2.0.18" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2025-06-11T11:19:37+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/6d584c727d9114bcdc14c86711cd1cad51778e7c", + "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for 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/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:53:50+00:00" + }, + { + "name": "sebastian/comparator", + "version": "7.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "03d905327dccc0851c9a08d6a979dfc683826b6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/03d905327dccc0851c9a08d6a979dfc683826b6f", + "reference": "03d905327dccc0851c9a08d6a979dfc683826b6f", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.2" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.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": "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/7.1.0" + }, + "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-06-17T07:41:58+00:00" + }, + { + "name": "sebastian/complexity", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "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/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "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/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "8.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "d364b9e5d0d3b18a2573351a1786fbf96b7e0792" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d364b9e5d0d3b18a2573351a1786fbf96b7e0792", + "reference": "d364b9e5d0d3b18a2573351a1786fbf96b7e0792", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-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/8.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T15:05:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "76432aafc58d50691a00d86d0632f1217a47b688" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/76432aafc58d50691a00d86d0632f1217a47b688", + "reference": "76432aafc58d50691a00d86d0632f1217a47b688", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "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/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:56:42+00:00" + }, + { + "name": "sebastian/global-state", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/570a2aeb26d40f057af686d63c4e99b075fb6cbc", + "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.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/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:56:59+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for 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/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:28+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:48+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.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": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:17+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/c405ae3a63e01b32eb71577f8ec1604e39858a7c", + "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "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/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T05:00:01+00:00" + }, + { + "name": "sebastian/type", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/1d7cd6e514384c36d7a390347f57c385d4be6069", + "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.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": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-18T13:37:31+00:00" + }, + { + "name": "sebastian/version", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T05:00:38+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "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" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": {}, diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..b94f410 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,12 @@ + + + + + ./tests + + + + diff --git a/src/Exception.php b/src/Exception.php new file mode 100644 index 0000000..2df5bc3 --- /dev/null +++ b/src/Exception.php @@ -0,0 +1,7 @@ +client = new InfernoClient('localhost', 4567, false); + } + + /** + * Helper method to call the private request method + * + * @param string $method + * @param string $endpoint + * @param array $params + * @param array $data + * @return array + */ + protected function callRequestMethod(string $method, string $endpoint, array $params = [], array $data = []): array + { + $reflection = new \ReflectionClass($this->client); + $requestMethod = $reflection->getMethod('request'); + $requestMethod->setAccessible(true); + + return $requestMethod->invoke($this->client, $method, $endpoint, $params, $data); + } + + /** + * Test that the base URL is constructed correctly + */ + public function testBaseUrlConstruction(): void + { + $reflection = new \ReflectionClass($this->client); + $baseUrlProperty = $reflection->getProperty('baseUrl'); + $baseUrlProperty->setAccessible(true); + + $this->assertEquals('http://localhost:4567/api', $baseUrlProperty->getValue($this->client)); + + // Test with HTTPS and default port + $httpsClient = new InfernoClient('example.com', 443, true); + $baseUrlProperty = $reflection->getProperty('baseUrl'); + $baseUrlProperty->setAccessible(true); + + $this->assertEquals('https://example.com/api', $baseUrlProperty->getValue($httpsClient)); + } + + /** + * Test that the client methods match the API endpoints in swagger.yml + * These tests validate the mapping between client methods and API endpoints + */ + public function testApiEndpointMappings(): void + { + // Get the methods defined in the InfernoClient class + $reflection = new \ReflectionClass($this->client); + $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); + + // Expected mappings between methods and endpoints + $expectedMappings = [ + 'getTestSuites' => '/test_suites', + 'getTestSuite' => '/test_suites/{testSuiteId}', + 'getTestSuiteRequirements' => '/test_suites/{testSuiteId}/requirements', + 'checkTestSuiteConfiguration' => '/test_suites/{testSuiteId}/check_configuration', + 'createTestSession' => '/test_sessions', + 'getTestSession' => '/test_sessions/{testSessionId}', + 'getTestSessionResults' => '/test_sessions/{testSessionId}/results', + 'getSessionData' => '/test_sessions/{testSessionId}/session_data', + 'applySessionDataPreset' => '/test_sessions/{testSessionId}/session_data/apply_preset', + 'createTestRun' => '/test_runs', + 'getTestRun' => '/test_runs/{testRunId}', + 'cancelTestRun' => '/test_runs/{testRunId}', + 'getLastTestRun' => '/test_sessions/{testSessionId}/last_test_run', + 'getTestRunResults' => '/test_runs/{testRunId}/results', + 'getRequest' => '/request/{requestId}', + 'getRequirement' => '/requirements/{requirementId}', + 'getVersion' => '/version' + ]; + + // Get the source code of the InfernoClient class + $source = file_get_contents(__DIR__ . '/../src/InfernoClient.php'); + + // Check that each expected endpoint is implemented + foreach ($expectedMappings as $methodName => $endpoint) { + // Check if the method exists + $this->assertTrue($reflection->hasMethod($methodName), + "Method $methodName should exist to handle $endpoint endpoint"); + + // For URLs with variable parts, only test for the fixed parts + $endpointBase = explode('{', $endpoint)[0]; + if ($endpointBase === $endpoint) { + // For fixed URLs, match exactly + $this->assertStringContainsString($endpoint, $source, + "Method $methodName should use the endpoint $endpoint"); + } else { + // For URLs with variable parts, match the base path + $this->assertStringContainsString($endpointBase, $source, + "Method $methodName should use the endpoint base $endpointBase"); + } + } + } + + /** + * Test that the method parameters match the API parameters + * This specifically tests method signatures against swagger.yml expectations + */ + public function testMethodParametersMatchApiDefinition(): void + { + $reflection = new \ReflectionClass($this->client); + + // Define expected method parameters + $methodParameters = [ + 'getTestSuites' => [], + 'getTestSuite' => ['testSuiteId'], + 'getTestSuiteRequirements' => ['testSuiteId', 'sessionId?'], + 'checkTestSuiteConfiguration' => ['testSuiteId'], + 'createTestSession' => ['testSuiteId', 'presetId?'], + 'getTestSession' => ['testSessionId'], + 'getTestSessionResults' => ['testSessionId', 'all?'], + 'getSessionData' => ['testSessionId'], + 'applySessionDataPreset' => ['testSessionId', 'presetId'], + 'createTestRun' => ['testRun'], + 'getTestRun' => ['testRunId', 'includeResults?', 'after?'], + 'cancelTestRun' => ['testRunId'], + 'getLastTestRun' => ['testSessionId'], + 'getTestRunResults' => ['testRunId'], + 'getRequest' => ['requestId'], + 'getRequirement' => ['requirementId'], + 'getVersion' => [] + ]; + + // Check parameters for each method + foreach ($methodParameters as $methodName => $expectedParams) { + $method = $reflection->getMethod($methodName); + $actualParams = $method->getParameters(); + + // Check parameter count + $this->assertCount(count($expectedParams), $actualParams, + "Method $methodName should have " . count($expectedParams) . " parameter(s)"); + + // Check each parameter + foreach ($expectedParams as $i => $paramName) { + $isOptional = str_ends_with($paramName, '?'); + $baseName = $isOptional ? substr($paramName, 0, -1) : $paramName; + + $this->assertEquals($baseName, $actualParams[$i]->getName(), + "Parameter $i of $methodName should be named $baseName"); + + if ($isOptional) { + $this->assertTrue($actualParams[$i]->isOptional(), + "Parameter $baseName of $methodName should be optional"); + } else { + $this->assertFalse($actualParams[$i]->isOptional(), + "Parameter $baseName of $methodName should be required"); + } + } + } + + // Test createTestSession method parameters + $method = $reflection->getMethod('createTestSession'); + $parameters = $method->getParameters(); + $this->assertCount(2, $parameters); + $this->assertEquals('testSuiteId', $parameters[0]->getName()); + $this->assertTrue($parameters[0]->isRequired()); + $this->assertEquals('presetId', $parameters[1]->getName()); + $this->assertFalse($parameters[1]->isRequired()); + } + + /** + * Test that the method return types match the API response types + */ + public function testMethodReturnTypesMatchApiDefinition(): void + { + $reflection = new \ReflectionClass($this->client); + + // Define expected return types + $methodReturnTypes = [ + 'getTestSuites' => 'array', + 'getTestSuite' => 'OpenCoreEmr\InfernoClient\Models\TestSuite', + 'getTestSuiteRequirements' => 'array', + 'checkTestSuiteConfiguration' => 'array', + 'createTestSession' => 'OpenCoreEmr\InfernoClient\Models\TestSession', + 'getTestSession' => 'OpenCoreEmr\InfernoClient\Models\TestSession', + 'getTestSessionResults' => 'array', + 'getSessionData' => 'array', + 'applySessionDataPreset' => 'bool', + 'createTestRun' => 'OpenCoreEmr\InfernoClient\Models\TestRun', + 'getTestRun' => 'OpenCoreEmr\InfernoClient\Models\TestRun', + 'cancelTestRun' => 'OpenCoreEmr\InfernoClient\Models\TestRun', + 'getLastTestRun' => 'OpenCoreEmr\InfernoClient\Models\TestRun', + 'getTestRunResults' => 'array', + 'getRequest' => 'OpenCoreEmr\InfernoClient\Models\Request', + 'getRequirement' => 'OpenCoreEmr\InfernoClient\Models\Requirement', + 'getVersion' => 'OpenCoreEmr\InfernoClient\Models\Version' + ]; + + // Check return type for each method + foreach ($methodReturnTypes as $methodName => $expectedType) { + $method = $reflection->getMethod($methodName); + $actualType = $method->getReturnType(); + + $this->assertNotNull($actualType, + "Method $methodName should have a return type"); + + $this->assertEquals($expectedType, $actualType->getName(), + "Method $methodName should return $expectedType"); + } + } +} diff --git a/tests/ModelDefinitionsTest.php b/tests/ModelDefinitionsTest.php new file mode 100644 index 0000000..21b1fc8 --- /dev/null +++ b/tests/ModelDefinitionsTest.php @@ -0,0 +1,406 @@ +assertTrue($reflection->hasProperty('version'), "Version model should have 'version' property"); + + // Test fromArray method + $versionData = ['version' => '1.0.0']; + $version = Version::fromArray($versionData); + $this->assertInstanceOf(Version::class, $version); + $this->assertEquals('1.0.0', $version->version); + } + + /** + * Test TestSuite model against swagger.yml definition + */ + public function testTestSuiteModel(): void + { + $reflection = new \ReflectionClass(TestSuite::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "TestSuite model should have 'id' property"); + $this->assertTrue($reflection->hasProperty('title'), "TestSuite model should have 'title' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('short_title'), "TestSuite model should have 'short_title' property"); + $this->assertTrue($reflection->hasProperty('description'), "TestSuite model should have 'description' property"); + $this->assertTrue($reflection->hasProperty('test_groups'), "TestSuite model should have 'test_groups' property"); + + // Test fromArray method + $testSuiteData = [ + 'id' => 'suite1', + 'title' => 'Test Suite 1', + 'description' => 'A test suite', + 'test_groups' => [ + ['id' => 'group1', 'title' => 'Group 1'] + ] + ]; + + $testSuite = TestSuite::fromArray($testSuiteData); + $this->assertInstanceOf(TestSuite::class, $testSuite); + $this->assertEquals('suite1', $testSuite->id); + $this->assertEquals('Test Suite 1', $testSuite->title); + } + + /** + * Test TestGroup model against swagger.yml definition + */ + public function testTestGroupModel(): void + { + $reflection = new \ReflectionClass(TestGroup::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "TestGroup model should have 'id' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('title'), "TestGroup model should have 'title' property"); + $this->assertTrue($reflection->hasProperty('tests'), "TestGroup model should have 'tests' property"); + + // Test fromArray method + $testGroupData = [ + 'id' => 'group1', + 'title' => 'Test Group 1', + 'tests' => [ + ['id' => 'test1', 'name' => 'Test 1'] + ] + ]; + + $testGroup = TestGroup::fromArray($testGroupData); + $this->assertInstanceOf(TestGroup::class, $testGroup); + $this->assertEquals('group1', $testGroup->id); + $this->assertEquals('Test Group 1', $testGroup->title); + } + + /** + * Test Test model against swagger.yml definition + */ + public function testTestModel(): void + { + $reflection = new \ReflectionClass(Test::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "Test model should have 'id' property"); + $this->assertTrue($reflection->hasProperty('title'), "Test model should have 'title' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('description'), "Test model should have 'description' property"); + $this->assertTrue($reflection->hasProperty('inputs'), "Test model should have 'inputs' property"); + + // Test fromArray method + $testData = [ + 'id' => 'test1', + 'title' => 'Test 1', + 'description' => 'A test', + 'inputs' => [ + ['name' => 'input1', 'value' => 'value1'] + ] + ]; + + $test = Test::fromArray($testData); + $this->assertInstanceOf(Test::class, $test); + $this->assertEquals('test1', $test->id); + $this->assertEquals('Test 1', $test->title); + } + + /** + * Test Input model against swagger.yml definition + */ + public function testInputModel(): void + { + $reflection = new \ReflectionClass(Input::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('name'), "Input model should have 'name' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('value'), "Input model should have 'value' property"); + $this->assertTrue($reflection->hasProperty('title'), "Input model should have 'title' property"); + + // Test fromArray method + $inputData = [ + 'name' => 'input1', + 'value' => 'value1', + 'title' => 'Input 1', + 'description' => 'An input', + 'optional' => true + ]; + + $input = Input::fromArray($inputData); + $this->assertInstanceOf(Input::class, $input); + $this->assertEquals('input1', $input->name); + $this->assertEquals('value1', $input->value); + } + + /** + * Test Requirement model against swagger.yml definition + */ + public function testRequirementModel(): void + { + $reflection = new \ReflectionClass(Requirement::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "Requirement model should have 'id' property"); + $this->assertTrue($reflection->hasProperty('requirement'), "Requirement model should have 'requirement' property"); + $this->assertTrue($reflection->hasProperty('conformance'), "Requirement model should have 'conformance' property"); + $this->assertTrue($reflection->hasProperty('actor'), "Requirement model should have 'actor' property"); + + // Test fromArray method + $requirementData = [ + 'id' => 'req1', + 'requirement' => 'Must support Patient resource', + 'conformance' => 'SHALL', + 'actor' => 'Client', + 'conditionality' => 'Optional', + 'url' => 'http://example.com/requirements' + ]; + + $requirement = Requirement::fromArray($requirementData); + $this->assertInstanceOf(Requirement::class, $requirement); + $this->assertEquals('req1', $requirement->id); + $this->assertEquals('Must support Patient resource', $requirement->requirement); + $this->assertEquals('SHALL', $requirement->conformance); + } + + /** + * Test Result model against swagger.yml definition + */ + public function testResultModel(): void + { + $reflection = new \ReflectionClass(Result::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "Result model should have 'id' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('result'), "Result model should have 'result' property"); + $this->assertTrue($reflection->hasProperty('result_message'), "Result model should have 'result_message' property"); + $this->assertTrue($reflection->hasProperty('requests'), "Result model should have 'requests' property"); + + // Test fromArray method + $resultData = [ + 'id' => 'result1', + 'test_id' => 'test1', + 'result' => 'pass', + 'result_message' => 'Test passed', + 'created_at' => '2025-06-18T12:00:00Z' + ]; + + $result = Result::fromArray($resultData); + $this->assertInstanceOf(Result::class, $result); + $this->assertEquals('result1', $result->id); + $this->assertEquals('pass', $result->result); + } + + /** + * Test Request model against swagger.yml definition + */ + public function testRequestModel(): void + { + $reflection = new \ReflectionClass(Request::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "Request model should have 'id' property"); + $this->assertTrue($reflection->hasProperty('index'), "Request model should have 'index' property"); + $this->assertTrue($reflection->hasProperty('created_at'), "Request model should have 'created_at' property"); + $this->assertTrue($reflection->hasProperty('verb'), "Request model should have 'verb' property"); + $this->assertTrue($reflection->hasProperty('url'), "Request model should have 'url' property"); + $this->assertTrue($reflection->hasProperty('direction'), "Request model should have 'direction' property"); + $this->assertTrue($reflection->hasProperty('result_id'), "Request model should have 'result_id' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('request_headers'), "Request model should have 'request_headers' property"); + $this->assertTrue($reflection->hasProperty('response_headers'), "Request model should have 'response_headers' property"); + + // Test fromArray method + $requestData = [ + 'id' => 'req1', + 'index' => 1, + 'created_at' => '2025-06-18T12:00:00Z', + 'verb' => 'GET', + 'url' => 'https://example.com/fhir/Patient/123', + 'direction' => 'out', + 'status' => 200, + 'result_id' => 'result1', + 'request_headers' => [['name' => 'Accept', 'value' => 'application/json']], + 'response_headers' => [['name' => 'Content-Type', 'value' => 'application/json']], + 'request_body' => '{}', + 'response_body' => '{"resourceType":"Patient"}' + ]; + + $request = Request::fromArray($requestData); + $this->assertInstanceOf(Request::class, $request); + $this->assertEquals('req1', $request->id); + $this->assertEquals('GET', $request->verb); + $this->assertEquals('out', $request->direction); + } + + /** + * Test RequestSummary model against swagger.yml definition + */ + public function testRequestSummaryModel(): void + { + $reflection = new \ReflectionClass(RequestSummary::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "RequestSummary model should have 'id' property"); + $this->assertTrue($reflection->hasProperty('index'), "RequestSummary model should have 'index' property"); + $this->assertTrue($reflection->hasProperty('created_at'), "RequestSummary model should have 'created_at' property"); + $this->assertTrue($reflection->hasProperty('verb'), "RequestSummary model should have 'verb' property"); + $this->assertTrue($reflection->hasProperty('url'), "RequestSummary model should have 'url' property"); + $this->assertTrue($reflection->hasProperty('direction'), "RequestSummary model should have 'direction' property"); + $this->assertTrue($reflection->hasProperty('result_id'), "RequestSummary model should have 'result_id' property"); + + // Test fromArray method + $requestSummaryData = [ + 'id' => 'req1', + 'index' => 1, + 'created_at' => '2025-06-18T12:00:00Z', + 'verb' => 'GET', + 'url' => 'https://example.com/fhir/Patient/123', + 'direction' => 'out', + 'status' => 200, + 'result_id' => 'result1' + ]; + + $requestSummary = RequestSummary::fromArray($requestSummaryData); + $this->assertInstanceOf(RequestSummary::class, $requestSummary); + $this->assertEquals('req1', $requestSummary->id); + $this->assertEquals('GET', $requestSummary->verb); + } + + /** + * Test Message model against swagger.yml definition + */ + public function testMessageModel(): void + { + $reflection = new \ReflectionClass(Message::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('type'), "Message model should have 'type' property"); + $this->assertTrue($reflection->hasProperty('message'), "Message model should have 'message' property"); + + // Test fromArray method + $messageData = [ + 'type' => 'info', + 'message' => 'Information message' + ]; + + $message = Message::fromArray($messageData); + $this->assertInstanceOf(Message::class, $message); + $this->assertEquals('info', $message->type); + $this->assertEquals('Information message', $message->message); + } + + /** + * Test TestSession model against swagger.yml definition + */ + public function testTestSessionModel(): void + { + $reflection = new \ReflectionClass(TestSession::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "TestSession model should have 'id' property"); + $this->assertTrue($reflection->hasProperty('test_suite'), "TestSession model should have 'test_suite' property"); + + // Test fromArray method + $testSessionData = [ + 'id' => 'session1', + 'test_suite' => [ + 'id' => 'suite1', + 'title' => 'Test Suite 1' + ] + ]; + + $testSession = TestSession::fromArray($testSessionData); + $this->assertInstanceOf(TestSession::class, $testSession); + $this->assertEquals('session1', $testSession->id); + } + + /** + * Test TestRun model against swagger.yml definition + */ + public function testTestRunModel(): void + { + $reflection = new \ReflectionClass(TestRun::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('id'), "TestRun model should have 'id' property"); + $this->assertTrue($reflection->hasProperty('test_session_id'), "TestRun model should have 'test_session_id' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('test_suite_id'), "TestRun model should have 'test_suite_id' property"); + $this->assertTrue($reflection->hasProperty('test_group_id'), "TestRun model should have 'test_group_id' property"); + $this->assertTrue($reflection->hasProperty('test_id'), "TestRun model should have 'test_id' property"); + + // Test fromArray method + $testRunData = [ + 'id' => 'run1', + 'test_session_id' => 'session1', + 'test_count' => 5, + 'inputs' => [ + ['name' => 'input1', 'value' => 'value1'] + ] + ]; + + $testRun = TestRun::fromArray($testRunData); + $this->assertInstanceOf(TestRun::class, $testRun); + $this->assertEquals('run1', $testRun->id); + $this->assertEquals('session1', $testRun->test_session_id); + } + + /** + * Test SessionData model against swagger.yml definition + */ + public function testSessionDataModel(): void + { + $reflection = new \ReflectionClass(SessionData::class); + + // Check required properties + $this->assertTrue($reflection->hasProperty('name'), "SessionData model should have 'name' property"); + + // Check optional properties + $this->assertTrue($reflection->hasProperty('value'), "SessionData model should have 'value' property"); + + // Test fromArray method + $sessionDataArray = [ + 'name' => 'param1', + 'value' => 'value1' + ]; + + $sessionData = SessionData::fromArray($sessionDataArray); + $this->assertInstanceOf(SessionData::class, $sessionData); + $this->assertEquals('param1', $sessionData->name); + $this->assertEquals('value1', $sessionData->value); + } +} diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..fd022f9 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,35 @@ +# Inferno Client PHP Tests + +This directory contains unit tests for the Inferno API PHP Client. The tests validate that the client methods align with the API endpoints defined in the swagger.yml specification. + +## Test Structure + +- `InfernoClientTest.php` - Tests for all API methods in the InfernoClient class +- `InfernoClientRequestTest.php` - Tests for the request method and error handling +- `ModelDefinitionsTest.php` - Tests to ensure model properties align with swagger.yml definitions + +## Running Tests + +You can run the tests using PHPUnit: + +```bash +vendor/bin/phpunit +``` + +## Test Coverage + +The tests cover: + +1. API endpoint mappings - Validating that client methods correctly map to swagger.yml endpoints +2. Request parameter handling - Ensuring parameters are passed correctly to the API +3. Response handling - Verifying that responses are parsed into the appropriate model objects +4. Error handling - Testing that API errors are properly caught and handled +5. Model definitions - Confirming that model properties match the swagger.yml schemas + +## Adding New Tests + +When adding new tests: + +1. For new API endpoints, add tests to `InfernoClientTest.php` +2. For model changes, update `ModelDefinitionsTest.php` +3. For request handling changes, update `InfernoClientRequestTest.php`