diff --git a/.gitignore b/.gitignore index 89c7fb0..d564ad1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,8 @@ composer.phar # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file # composer.lock +.hurc-harness/ +__pycache__/ +*.pyc +.phpunit.result.cache +.phpunit.cache/ diff --git a/composer.json b/composer.json index f8d4bac..032e2f1 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ } ], "scripts": { - "phpcs": "./vendor/bin/phpcs --extensions=php -p ." + "phpcs": "./vendor/bin/phpcs --extensions=php -p .", + "test": "phpunit --no-coverage" }, "autoload": { "psr-4": { @@ -19,6 +20,12 @@ } }, "require-dev": { - "squizlabs/php_codesniffer": "*" + "squizlabs/php_codesniffer": "*", + "phpunit/phpunit": "^10.5" + }, + "autoload-dev": { + "psr-4": { + "Ahamed\\Jext\\Tests\\": "tests/" + } } } diff --git a/composer.lock b/composer.lock index 3b5a5de..72fb7d3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,1611 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "68f0ad47378c538eaa2a01c68f60f156", + "content-hash": "6d2ec1dc8fcee22b7f13444ea19c2e08", "packages": [], "packages-dev": [ + { + "name": "myclabs/deep-copy", + "version": "1.14.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "8680aa248f8e07bc8fb43f56f0f5fc77a0c96aae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8680aa248f8e07bc8fb43f56f0f5fc77a0c96aae", + "reference": "8680aa248f8e07bc8fb43f56f0f5fc77a0c96aae", + "shasum": "" + }, + "require": { + "php": "^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.14.0" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2026-08-11T10:17:44+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.8.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "shasum": "" + }, + "require": { + "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.8.0" + }, + "time": "2026-07-04T14:30:18+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": "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.64", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "0e8c1d19cea35ad97d4887f363d07c78e30fbf06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e8c1d19cea35ad97d4887f363d07c78e30fbf06", + "reference": "0e8c1d19cea35ad97d4887f363d07c78e30fbf06", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-filter": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "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.5", + "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.64" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsoring.html", + "type": "other" + } + ], + "time": "2026-07-06T14:50:35+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.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d", + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d", + "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.5" + }, + "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": "2026-01-24T09:25:16+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.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5d32fe257a9b39cb63146924d6b4e32a22d4502a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5d32fe257a9b39cb63146924d6b4e32a22d4502a", + "reference": "5d32fe257a9b39cb63146924d6b4e32a22d4502a", + "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.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/recursion-context", + "type": "tidelift" + } + ], + "time": "2026-08-11T05:27:39+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": "squizlabs/php_codesniffer", "version": "3.5.8", @@ -62,14 +1664,64 @@ "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, "time": "2020-10-23T02:01:07+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", + "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.3.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-11-17T20:03:58+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "plugin-api-version": "2.0.0" + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/configs/complete-e2e/list-runtime-clis.sh b/configs/complete-e2e/list-runtime-clis.sh new file mode 100755 index 0000000..897c7f4 --- /dev/null +++ b/configs/complete-e2e/list-runtime-clis.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# ----------------------------------------------------------------------------- +# Goal : Emit jext-cli CLI surfaces as JSON for complete-e2e compile. +# Purpose : Dual-origin runtime discovery matching static cli:jext-cli. +# Consumers: configs/complete-e2e/runtime.json adapter jext-cli-runtime. +# Outputs : stdout JSON {surfaces:[...]} only. +# Exit codes: 0 ok / 1 missing python3 +# Side effects: none. +# ----------------------------------------------------------------------------- +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +command -v python3 >/dev/null 2>&1 || { echo "python3 required" >&2; exit 1; } +python3 - "$ROOT" <<'PY' +import json, sys +from pathlib import Path + +root = Path(sys.argv[1]) +candidates = [ + ("cli:jext-cli", "devtools/jext-cli/run.sh"), +] +surfaces = [] +for sid, rel in candidates: + p = root / rel + if p.is_file(): + surfaces.append({ + "id": sid, + "kind": "cli", + "path": rel, + "origin": "runtime", + "discovered": True, + }) +print(json.dumps({"surfaces": surfaces})) +PY diff --git a/configs/complete-e2e/runtime.json b/configs/complete-e2e/runtime.json new file mode 100644 index 0000000..6a5b7a0 --- /dev/null +++ b/configs/complete-e2e/runtime.json @@ -0,0 +1,13 @@ +{ + "schema": "hurc-complete-e2e-runtime/v1", + "description": "CLI adapter so CJ-Hurc/jext-cli compile reconciles dual-origin cli:jext-cli (static devtools run.sh + runtime list). PHP bin/ is the product; run.sh is the occupancy driver.", + "adapters": [ + { + "id": "jext-cli-runtime", + "kind": "cli", + "surface_kind": "cli", + "timeout_sec": 15, + "argv": ["bash", "configs/complete-e2e/list-runtime-clis.sh"] + } + ] +} diff --git a/devtools/jext-cli/run.sh b/devtools/jext-cli/run.sh new file mode 100755 index 0000000..1a2c5e5 --- /dev/null +++ b/devtools/jext-cli/run.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# ----------------------------------------------------------------------------- +# Goal : First-party CLI for CJ-Hurc/jext-cli (PHP Joomla component builder). +# Purpose : status/--help print usage (no side effects). validate checks +# README + PHP bin + runtime discovery + occupancy prove contracts. +# Consumers: humans, CI, complete-e2e CLI contract / universal scaffold. +# Exit codes: 0 help/status/validate/config/version / 1 contract fail / 2 usage +# Side effects: none for help/status/config/validate/version (file reads only). +# ----------------------------------------------------------------------------- +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" + +usage() { + cat <<'USAGE' +usage: devtools/jext-cli/run.sh + status / --help Print this help (no side effects). + config List first-party entrypoints. + validate Fail-closed contract checks on README + CLI + runtime discovery. + version Print jext-cli version via PHP bin (requires composer install). +First-party surfaces: README.md, run.sh, bin/jext-cli, devtools/jext-cli/run.sh, +configs/complete-e2e/runtime.json, configs/complete-e2e/list-runtime-clis.sh, +scripts/complete-e2e/prove/{entity,repository}.py. +USAGE +} + +require_file() { + local rel="$1" + [[ -f "$ROOT/$rel" ]] || { echo "validate fail: missing $rel" >&2; return 1; } +} + +cmd="${1:-}" +case "$cmd" in + status|--help|-h|help) + usage + exit 0 + ;; + "") + usage >&2 + exit 2 + ;; + config) + printf '%s\n' \ + 'README.md' \ + 'run.sh' \ + 'bin/jext-cli' \ + 'devtools/jext-cli/run.sh' \ + 'configs/complete-e2e/runtime.json' \ + 'configs/complete-e2e/list-runtime-clis.sh' \ + 'scripts/complete-e2e/prove/entity.py' \ + 'scripts/complete-e2e/prove/repository.py' + ;; + version) + command -v php >/dev/null 2>&1 || { echo "php missing" >&2; exit 1; } + [[ -f "$ROOT/vendor/autoload.php" ]] || { echo "vendor/autoload.php missing — run composer install" >&2; exit 1; } + php "$ROOT/bin/jext-cli" --version + ;; + validate) + require_file "README.md" + require_file "run.sh" + require_file "bin/jext-cli" + require_file "devtools/jext-cli/run.sh" + require_file "configs/complete-e2e/runtime.json" + require_file "configs/complete-e2e/list-runtime-clis.sh" + require_file "scripts/complete-e2e/prove/entity.py" + require_file "scripts/complete-e2e/prove/repository.py" + require_file "composer.json" + require_file "phpunit.xml" + require_file "tests/CompleteE2e/CompleteE2eLibraryContractTest.php" + grep -qi 'jext-cli\|JEXT-CLI' "$ROOT/README.md" || { echo "validate fail: README identity" >&2; exit 1; } + grep -q 'JEXT_CLI_ALLOWED' "$ROOT/run.sh" || { echo "validate fail: root allow gate" >&2; exit 1; } + grep -q 'usage:' "$ROOT/devtools/jext-cli/run.sh" || { echo "validate fail: CLI usage banner" >&2; exit 1; } + grep -q 'hurc-complete-e2e-runtime/v1' "$ROOT/configs/complete-e2e/runtime.json" || { echo "validate fail: runtime schema" >&2; exit 1; } + grep -q 'jext-cli-runtime' "$ROOT/configs/complete-e2e/runtime.json" || { echo "validate fail: runtime adapter id" >&2; exit 1; } + grep -q 'cli:jext-cli' "$ROOT/configs/complete-e2e/list-runtime-clis.sh" || { echo "validate fail: runtime surface id" >&2; exit 1; } + head -1 "$ROOT/bin/jext-cli" | grep -q 'php' || { echo "validate fail: bin/jext-cli shebang" >&2; exit 1; } + # Live PHP exec when vendor is present (clean-room worktrees omit gitignored vendor). + if [[ -f "$ROOT/vendor/autoload.php" ]] && command -v php >/dev/null 2>&1; then + php "$ROOT/bin/jext-cli" --version | grep -qi 'jext-cli\|version' || { echo "validate fail: php bin --version" >&2; exit 1; } + fi + echo "ok jext-cli validate" + ;; + *) + echo "unknown command: $cmd" >&2 + usage >&2 + exit 2 + ;; +esac diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..f7deba5 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,12 @@ + + + + + tests + + + diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..5ca789f --- /dev/null +++ b/run.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# ----------------------------------------------------------------------------- +# Goal : Fail-closed root entry for CJ-Hurc/jext-cli. +# Purpose : Refuse direct execution unless JEXT_CLI_ALLOWED=yes; then +# delegate to the first-party CLI under devtools/. +# Consumers: humans, CI, complete-e2e repository occupancy (missing-env). +# Exit codes: 0 delegated / 1 blocked without allow / delegated +# Side effects: none when blocked; otherwise same as CLI. +# ----------------------------------------------------------------------------- +if [[ "${JEXT_CLI_ALLOWED:-}" != "yes" ]]; then + echo "This script should not be run directly." + exit 1 +fi +ROOT="$(cd "$(dirname "$0")" && pwd)" +exec bash "$ROOT/devtools/jext-cli/run.sh" "$@" diff --git a/scripts/complete-e2e/fault/invalid-config.sh b/scripts/complete-e2e/fault/invalid-config.sh new file mode 100755 index 0000000..254422e --- /dev/null +++ b/scripts/complete-e2e/fault/invalid-config.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -uo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +cd "$ROOT" || exit 2 +fail() { echo "FAIL: $*" >&2; exit 1; } +ok() { echo "ok - $*"; } +if bash devtools/jext-cli/run.sh not-a-real-command >/dev/null 2>&1; then + fail "unknown command should fail" +fi +ok "devtools unknown-command fail-closed" +if bash devtools/jext-cli/run.sh --hurc-ce2e-no-such-flag >/dev/null 2>&1; then + fail "unknown flag should fail" +fi +ok "devtools unknown-flag fail-closed" +echo "PASS invalid-config" +exit 0 diff --git a/scripts/complete-e2e/fault/missing-env.sh b/scripts/complete-e2e/fault/missing-env.sh new file mode 100755 index 0000000..6b990b7 --- /dev/null +++ b/scripts/complete-e2e/fault/missing-env.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -uo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +cd "$ROOT" || exit 2 +fail() { echo "FAIL: $*" >&2; exit 1; } +ok() { echo "ok - $*"; } +if JEXT_CLI_ALLOWED=no bash run.sh >/dev/null 2>&1; then + fail "run.sh should fail without JEXT_CLI_ALLOWED=yes" +fi +ok "run.sh missing-allow fail-closed" +echo "PASS missing-env" +exit 0 diff --git a/scripts/complete-e2e/prove.sh b/scripts/complete-e2e/prove.sh new file mode 100755 index 0000000..44ae582 --- /dev/null +++ b/scripts/complete-e2e/prove.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# Machine-prove jext-cli (dual-origin CLI runtime + occupancy + proof-receipt). +set -uo pipefail +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + echo "Usage: scripts/complete-e2e/prove.sh" + echo "Help: prove dual-origin CLI + occupancy scripts + PHP library contract." + exit 0 +fi +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT" || exit 2 +fail=0 +pass() { printf 'PASS %s\n' "$*"; } +fail_one() { printf 'FAIL %s\n' "$*"; fail=1; } + +bash configs/complete-e2e/list-runtime-clis.sh | grep -q '"id": "cli:jext-cli"' && pass "runtime cli:jext-cli" || fail_one "runtime missing cli:jext-cli" +[[ -f configs/complete-e2e/runtime.json ]] && pass "runtime.json" || fail_one "runtime.json missing" +[[ -f devtools/jext-cli/run.sh ]] && pass "devtools/jext-cli/run.sh" || fail_one "devtools missing" +[[ -f bin/jext-cli ]] && pass "bin/jext-cli" || fail_one "bin missing" +[[ -f scripts/complete-e2e/prove/repository.py ]] && pass "repository.py" || fail_one "repository.py missing" +[[ -f scripts/complete-e2e/prove/entity.py ]] && pass "entity.py" || fail_one "entity.py missing" + +if bash devtools/jext-cli/run.sh validate; then + pass "cli validate" +else + fail_one "cli validate" +fi +if bash devtools/jext-cli/run.sh status >/dev/null; then + pass "cli status" +else + fail_one "cli status" +fi +help_out="$(bash devtools/jext-cli/run.sh --help 2>&1 || true)" +printf '%s' "$help_out" | grep -qiE 'usage|status|validate' && pass "cli --help" || fail_one "cli --help" + +if bash scripts/complete-e2e/fault/missing-env.sh; then + pass "occupancy missing-env" +else + fail_one "occupancy missing-env" +fi +if bash scripts/complete-e2e/fault/invalid-config.sh; then + pass "occupancy invalid-config" +else + fail_one "occupancy invalid-config" +fi + +if [[ -x vendor/bin/phpunit ]]; then + if php vendor/bin/phpunit -c phpunit.xml --no-coverage; then + pass "phpunit library contract" + else + fail_one "phpunit library contract" + fi +else + fail_one "vendor/bin/phpunit missing" +fi + +[[ "$fail" -eq 0 ]] || exit 1 +printf 'OK jext-cli-complete-e2e-prove\n' +exit 0 diff --git a/scripts/complete-e2e/prove/entity.py b/scripts/complete-e2e/prove/entity.py new file mode 100644 index 0000000..bc7dd2a --- /dev/null +++ b/scripts/complete-e2e/prove/entity.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +"""Occupancy entrypoint auto-run by complete-e2e (_ensure_product_occupancy). + +Delegates to repository.py so universal missing-env/invalid-config receipts +survive the prove-dir stale-receipt clear. +""" +from __future__ import annotations + +import importlib.util +from pathlib import Path + + +def main() -> int: + path = Path(__file__).with_name("repository.py") + spec = importlib.util.spec_from_file_location("jext_cli_repository_prove", path) + if spec is None or spec.loader is None: + print("{" + '"ok": false, "error": "repository.py missing"' + "}") + return 1 + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return int(mod.main()) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/complete-e2e/prove/repository.py b/scripts/complete-e2e/prove/repository.py new file mode 100644 index 0000000..c412eae --- /dev/null +++ b/scripts/complete-e2e/prove/repository.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 +"""Identity-bound universal repository occupancy for CJ-Hurc/jext-cli.""" +from __future__ import annotations + +import json +import os +import sqlite3 +import subprocess +import tempfile +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[3] +_local_state = ROOT / ".hurc-harness" / "state" / "complete-e2e" +_local_active = _local_state / "active-run.json" +if _local_active.is_file(): + _ORIGIN = ROOT.resolve() +else: + _ORIGIN = Path(os.environ.get("HURC_CE2E_REPLAY_ORIGIN") or ROOT).resolve() +STATE = _ORIGIN / ".hurc-harness" / "state" / "complete-e2e" +SCENARIOS = ("missing-env", "startup", "cleanup", "invalid-config", "build") + + +def _run(argv: list[str], *, env: dict[str, str] | None = None, timeout: int = 30) -> subprocess.CompletedProcess[str]: + merged = os.environ.copy() + if env: + merged.update(env) + return subprocess.run( + argv, + cwd=str(ROOT), + env=merged, + capture_output=True, + text=True, + timeout=timeout, + check=False, + ) + + +def prove(scenario: str) -> dict[str, object]: + stack = ROOT / "devtools" / "jext-cli" / "run.sh" + legacy = ROOT / "run.sh" + php_bin = ROOT / "bin" / "jext-cli" + if scenario == "startup": + proc = _run(["bash", str(stack), "help"]) + text = f"{proc.stdout}\n{proc.stderr}".lower() + ok = proc.returncode == 0 and ("usage" in text or "help" in text) + return { + "ok": ok, + "evidence_refs": ["devtools/jext-cli/run.sh", "startup-help"], + } + if scenario == "build": + checks = [ + _run(["bash", str(stack), "validate"]), + _run(["bash", str(stack), "status"]), + _run(["bash", str(stack), "config"]), + ] + ok = all(p.returncode == 0 for p in checks) + ok = ok and php_bin.is_file() + ok = ok and (ROOT / "README.md").is_file() + ok = ok and (ROOT / "configs" / "complete-e2e" / "runtime.json").is_file() + ok = ok and (ROOT / "configs" / "complete-e2e" / "list-runtime-clis.sh").is_file() + ok = ok and (ROOT / "composer.json").is_file() + ok = ok and (ROOT / "phpunit.xml").is_file() + ok = ok and (ROOT / "tests" / "CompleteE2e" / "CompleteE2eLibraryContractTest.php").is_file() + # Optional live PHP when vendor exists (gitignored; clean-room may omit it). + if (ROOT / "vendor" / "autoload.php").is_file(): + ver = _run(["bash", str(stack), "version"]) + ok = ok and ver.returncode == 0 + return { + "ok": ok, + "evidence_refs": [ + "devtools/jext-cli/run.sh", + "bin/jext-cli", + "README.md", + "composer.json", + "phpunit.xml", + "tests/CompleteE2e/CompleteE2eLibraryContractTest.php", + "configs/complete-e2e/runtime.json", + "configs/complete-e2e/list-runtime-clis.sh", + "entrypoint-validate-smoke", + ], + } + if scenario == "cleanup": + with tempfile.TemporaryDirectory(prefix="jext-cli-ce2e-cleanup-") as scratch: + marker = Path(scratch) / "marker" + marker.write_text("temporary", encoding="utf-8") + ok = marker.is_file() + ok = ok and not Path(scratch).exists() + return {"ok": ok, "evidence_refs": ["temporary-directory-cleanup", "no-state-leak"]} + if scenario == "missing-env": + proc = _run(["bash", str(legacy)], env={"JEXT_CLI_ALLOWED": "no"}) + text = f"{proc.stdout}\n{proc.stderr}".lower() + ok = proc.returncode != 0 and ( + "should not be run directly" in text or "jext_cli_allowed" in text + ) + return { + "ok": ok, + "evidence_refs": ["run.sh", "jext-cli-allowed-fail-closed"], + } + if scenario == "invalid-config": + proc = _run(["bash", str(stack), "not-a-real-command"]) + text = f"{proc.stdout}\n{proc.stderr}".lower() + ok = proc.returncode != 0 and ("unknown" in text or "usage" in text) + return { + "ok": ok, + "evidence_refs": ["devtools/jext-cli/run.sh", "invalid-command-fail-closed"], + } + return {"ok": False, "evidence_refs": ["unknown-scenario"]} + + +def _identity() -> tuple[str, str, str]: + active = STATE / "active-run.json" + if not active.is_file(): + return "", "", "" + try: + run_id = str(json.loads(active.read_text(encoding="utf-8")).get("run_id") or "") + run_dir = STATE / "runs" / run_id + run = json.loads((run_dir / "run.json").read_text(encoding="utf-8")) + compile_doc = json.loads((run_dir / "compile.json").read_text(encoding="utf-8")) + universe = compile_doc.get("universe") or {} + snap = str(run.get("snapshot_id") or "") + uni = str(compile_doc.get("universe_id") or universe.get("id") or "") + return snap, uni, run_id + except (OSError, json.JSONDecodeError, AttributeError, TypeError): + return "", "", "" + + +def main() -> int: + snap, uni, run_id = _identity() + if not all((snap, uni, run_id)): + print(json.dumps({"ok": False, "error": "no-active-run-identity"})) + return 1 + run_dir = STATE / "runs" / run_id + db = run_dir / "cells.sqlite" + if not db.is_file(): + print(json.dumps({"ok": False, "error": "no-cells-db"})) + return 1 + scenarios = {s: prove(s) for s in SCENARIOS} + con = sqlite3.connect(str(db)) + con.row_factory = sqlite3.Row + rows = list( + con.execute( + "SELECT cell_id, scenario, snapshot_id, universe_id FROM cells " + "WHERE surface_id='capability:repository' AND pack='universal'" + ) + ) + con.close() + receipts = run_dir / "receipts" + receipts.mkdir(parents=True, exist_ok=True) + written = 0 + for row in rows: + scenario = str(row["scenario"] or "") + result = scenarios.get(scenario) or {} + if result.get("ok") is not True: + continue + if str(row["snapshot_id"] or "") != snap or str(row["universe_id"] or "") != uni: + continue + doc = { + "schema": "hurc-complete-e2e-named-receipt/v1", + "ok": True, + "cell_id": row["cell_id"], + "snapshot_id": snap, + "universe_id": uni, + "run_id": run_id, + "surface_id": "capability:repository", + "pack": "universal", + "scenario": scenario, + "prover": "jext-cli-repository-occupancy", + "evidence_refs": list(result.get("evidence_refs") or []) + ["repository-occupancy"], + } + (receipts / f"{row['cell_id']}.json").write_text(json.dumps(doc, indent=2) + "\n", encoding="utf-8") + for other in (STATE / "runs").glob("*/receipts"): + if other.parent.name == run_id: + continue + stale = other / f"{row['cell_id']}.json" + if stale.is_file(): + stale.unlink() + written += 1 + out = { + "ok": all(scenarios[s].get("ok") is True for s in SCENARIOS), + "scenarios": scenarios, + "named_receipts": written, + "run_id": run_id, + } + print(json.dumps(out)) + return 0 if out["ok"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/complete-e2e/prove/t0.sh b/scripts/complete-e2e/prove/t0.sh new file mode 100755 index 0000000..95d4a66 --- /dev/null +++ b/scripts/complete-e2e/prove/t0.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# Auto-run by complete-e2e _ensure_product_occupancy (stem: t0). +set -uo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +exec python3 "$ROOT/scripts/complete-e2e/prove/repository.py" diff --git a/tests/CompleteE2e/CompleteE2eLibraryContractTest.php b/tests/CompleteE2e/CompleteE2eLibraryContractTest.php new file mode 100644 index 0000000..2535e52 --- /dev/null +++ b/tests/CompleteE2e/CompleteE2eLibraryContractTest.php @@ -0,0 +1,55 @@ +getRegistry(''); + } catch (\InvalidArgumentException $e) { + $threw = true; + self::assertNotSame('', $e->getMessage()); + } catch (\Throwable $e) { + $threw = true; + self::assertNotSame('', $e->getMessage()); + } + self::assertTrue($threw, 'empty/unregistered registry lookup must throw'); + } + + public function testErrorSemanticsThrowOnDocumentedFault(): void + { + $threw = false; + try { + $registry = new Registry(); + $registry->getRegistry('--not-registered-command--'); + } catch (\InvalidArgumentException $e) { + $threw = true; + self::assertStringContainsString('not registered', $e->getMessage()); + } catch (\Throwable $e) { + $threw = true; + self::assertNotSame('', $e->getMessage()); + } + self::assertTrue($threw, 'documented registry fault must throw'); + } +}