diff --git a/README.md b/README.md index 50bde23..887b4cc 100644 --- a/README.md +++ b/README.md @@ -1,121 +1,125 @@ -# Sendama CLI — Console Application for the Sendama 2D Game Engine -by amasiye313@gmail.com - -## What is it? - -Sendama CLI is a console application that provides a command line interface for the Sendama 2D Game Engine. It is used to create, build, run and manage Sendama projects. - -![Screenshot](docs/screenshot.png) - -## Requirements - -- PHP 8.3 or newer -- WSL (For Windows) -- Composer 2.7.1 or later -- Sendama 2D Game Engine - -## Installation - -### For Linux, BSD etc - -To install Sendama CLI, run the following command in your terminal: -```bash -composer global require sendamaphp/console -``` - -If you haven't already, add Composer's system-wide vendor bin directory to your $PATH. This directory is at `~/.composer/vendor/bin` or `~/.config/composer/vendor/bin`. - -```bash -export PATH="$PATH:$HOME/.composer/vendor/bin" -``` - -Alternatively, you can link the `sendama` executable to a directory that is already in your $PATH. For example, you can link it to `/usr/local/bin`: - -```bash -sudo ln -s ~/.composer/vendor/bin/sendama /usr/local/bin/sendama -``` - -or - -```bash -sudo ln -s ~/.config/composer/vendor/bin/sendama /usr/local/bin/sendama -``` - -Then, you can run the `sendama` command in your terminal. - -```bash -sendama --help -``` - -### For Windows -From the WSL terminal follow Linux instructions - -### OSX -From the OSX terminal follow Linux instructions - -## Usage -```bash -sendama [command] [options] [arguments] -``` - -### Options -- `--help` or `-h` displays help for the command -- `--quiet` or `-q` suppresses output -- `--verbose` or `-v|vv|vvv` increases output verbosity -- `--version` or `-V` displays the application version -- `--ansi` or `-a` forces ANSI output -- `--no-ansi` or `-A` disables ANSI output -- `--no-interaction` or `-n` disables interaction - -### Available Commands - -#### Completion - -Dump shell completion code for the specified shell (bash, fish, zsh, or PowerShell). -```bash -sendama completion -``` - -#### Help - -Displays help for a command -```bash -sendama help -``` - -#### List - -Lists commands -```bash -sendama list -``` - -#### Create a new project - -Create a new Sendama project -```bash -sendama new:game mygame -``` -or -```bash -sendama new mygame -``` - -#### Arguments -- `name` is the name of the project -- `directory` is the path to the project directory - -### Generate a new scene -```bash -sendama generate:scene myscene -``` - -### Generate a new texture -```bash -sendama generate:texture mytexture -``` - -#### Generate a new texture with a specific size -```bash -sendama generate:texture mytexture --width=32 --height=32 +
+ Sendama 2d Game Engine +
+ +# Sendama CLI — Console Application for the Sendama 2D Game Engine +by amasiye313@gmail.com + +## What is it? + +Sendama CLI is a console application that provides a command line interface for the Sendama 2D Game Engine. It is used to create, build, run and manage Sendama projects. + +![Screenshot](docs/screenshot.png) + +## Requirements + +- PHP 8.3 or newer +- WSL (For Windows) +- Composer 2.7.1 or later +- Sendama 2D Game Engine + +## Installation + +### For Linux, BSD etc + +To install Sendama CLI, run the following command in your terminal: +```bash +composer global require sendamaphp/console +``` + +If you haven't already, add Composer's system-wide vendor bin directory to your $PATH. This directory is at `~/.composer/vendor/bin` or `~/.config/composer/vendor/bin`. + +```bash +export PATH="$PATH:$HOME/.composer/vendor/bin" +``` + +Alternatively, you can link the `sendama` executable to a directory that is already in your $PATH. For example, you can link it to `/usr/local/bin`: + +```bash +sudo ln -s ~/.composer/vendor/bin/sendama /usr/local/bin/sendama +``` + +or + +```bash +sudo ln -s ~/.config/composer/vendor/bin/sendama /usr/local/bin/sendama +``` + +Then, you can run the `sendama` command in your terminal. + +```bash +sendama --help +``` + +### For Windows +From the WSL terminal follow Linux instructions + +### OSX +From the OSX terminal follow Linux instructions + +## Usage +```bash +sendama [command] [options] [arguments] +``` + +### Options +- `--help` or `-h` displays help for the command +- `--quiet` or `-q` suppresses output +- `--verbose` or `-v|vv|vvv` increases output verbosity +- `--version` or `-V` displays the application version +- `--ansi` or `-a` forces ANSI output +- `--no-ansi` or `-A` disables ANSI output +- `--no-interaction` or `-n` disables interaction + +### Available Commands + +#### Completion + +Dump shell completion code for the specified shell (bash, fish, zsh, or PowerShell). +```bash +sendama completion +``` + +#### Help + +Displays help for a command +```bash +sendama help +``` + +#### List + +Lists commands +```bash +sendama list +``` + +#### Create a new project + +Create a new Sendama project +```bash +sendama new:game mygame +``` +or +```bash +sendama new mygame +``` + +#### Arguments +- `name` is the name of the project +- `directory` is the path to the project directory + +### Generate a new scene +```bash +sendama generate:scene myscene +``` + +### Generate a new texture +```bash +sendama generate:texture mytexture +``` + +#### Generate a new texture with a specific size +```bash +sendama generate:texture mytexture --width=32 --height=32 ``` \ No newline at end of file diff --git a/bin/sendama b/bin/sendama index 903a03a..f2bdcda 100755 --- a/bin/sendama +++ b/bin/sendama @@ -1,6 +1,7 @@ #!/usr/bin/env php addCommands([ new NewGame(), new PlayGame(), + new EditGame(), new GeneratePrefab(), new GenerateEvent(), new GenerateScene(), diff --git a/composer.json b/composer.json index 5a3a0a6..313a48a 100644 --- a/composer.json +++ b/composer.json @@ -2,13 +2,11 @@ "name": "sendamaphp/console", "type": "library", "description": "A simple CLI for creating and managing sendama-engine projects.", - "require-dev": { - "pestphp/pest": "^2.34" - }, "license": "MIT", "autoload": { "psr-4": { - "Sendama\\Console\\": "src/" + "Sendama\\Console\\": "src/", + "Atatusoft\\Termutil\\": "/home/amasiye/development/atatusoft/projects/external/termutil/src/" }, "files": [ "src/Util/Functions.php" @@ -21,10 +19,11 @@ } ], "require": { - "php": ">=8.3", + "php": "^8.4", "symfony/console": "^7.0", "amasiye/figlet": "^1.2", - "vlucas/phpdotenv": "^5.6" + "vlucas/phpdotenv": "^5.6", + "atatusoft-ltd/termutil": "^1.1" }, "config": { "allow-plugins": { diff --git a/composer.lock b/composer.lock index a30458f..43323ed 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "77d89e4d511acc0f6c0db0bc4b4d795e", + "content-hash": "8364fb1f6301a3ea496ad1e53b186692", "packages": [ { "name": "amasiye/figlet", @@ -65,26 +65,121 @@ }, "time": "2024-05-20T14:35:35+00:00" }, + { + "name": "assegaiphp/collections", + "version": "0.3.4", + "source": { + "type": "git", + "url": "https://github.com/assegaiphp/collections.git", + "reference": "eec7ee56dd024b3f4d9ea11eb3b200c009c6ceda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/assegaiphp/collections/zipball/eec7ee56dd024b3f4d9ea11eb3b200c009c6ceda", + "reference": "eec7ee56dd024b3f4d9ea11eb3b200c009c6ceda", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "pestphp/pest": "^2.6" + }, + "type": "library", + "autoload": { + "files": [ + "src/Util/Functions.php" + ], + "psr-4": { + "Assegai\\Collections\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrew Masiye", + "email": "andrew.masiye@assegaiphp.com" + } + ], + "description": "The assegaiphp/collections package is a powerful tool for creating and managing groups of related objects in your AssegaiPHP projects. With this library, you can easily organize and manipulate data in a variety of ways, such as arrays, lists, sets, and maps. The package offers a wide range of methods for adding, removing, and manipulating items, as well as sorting, searching, and filtering your collections. It is fully compatible with PHP 7.x and above and is designed to be lightweight and easy to use. Whether you're building a web application, a CLI tool, or a standalone script, assegaiphp/collections is the perfect choice for working with data. With its simple and intuitive interface, you can easily start working with collections in your project right away.", + "support": { + "issues": "https://github.com/assegaiphp/collections/issues", + "source": "https://github.com/assegaiphp/collections/tree/0.3.4" + }, + "time": "2025-03-08T22:03:19+00:00" + }, + { + "name": "atatusoft-ltd/termutil", + "version": "1.1.12", + "source": { + "type": "git", + "url": "https://github.com/atatusoft-ltd/termutil.git", + "reference": "d38fc06d218526453dbe6cac261ab96ac1012421" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/atatusoft-ltd/termutil/zipball/d38fc06d218526453dbe6cac261ab96ac1012421", + "reference": "d38fc06d218526453dbe6cac261ab96ac1012421", + "shasum": "" + }, + "require": { + "assegaiphp/collections": "^0.3.4", + "php": "^8.4" + }, + "require-dev": { + "pestphp/pest": "^4.3", + "phpstan/phpstan": "^2.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/Constants.php", + "src/Functions.php" + ], + "psr-4": { + "Atatusoft\\Termutil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrew Masiye", + "email": "amasiye313@gmail.com" + } + ], + "description": "A collection of utilities to help control ANSI powered terminals.", + "support": { + "issues": "https://github.com/atatusoft-ltd/termutil/issues", + "source": "https://github.com/atatusoft-ltd/termutil/tree/1.1.12" + }, + "time": "2026-02-21T21:44:50+00:00" + }, { "name": "graham-campbell/result-type", - "version": "v1.1.3", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", "autoload": { @@ -113,7 +208,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -125,20 +220,20 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { @@ -146,7 +241,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -188,7 +283,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -200,7 +295,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { "name": "psr/container", @@ -257,23 +352,24 @@ }, { "name": "symfony/console", - "version": "v7.0.7", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986" + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c981e0e9380ce9f146416bde3150c79197ce9986", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986", + "url": "https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894", + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^6.4|^7.0" + "symfony/string": "^7.2|^8.0" }, "conflict": { "symfony/dependency-injection": "<6.4", @@ -287,16 +383,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -330,7 +426,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.0.7" + "source": "https://github.com/symfony/console/tree/v7.4.4" }, "funding": [ { @@ -341,25 +437,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2026-01-13T11:36:38+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -367,12 +467,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -397,7 +497,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -413,24 +513,24 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -441,8 +541,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -476,7 +576,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -487,29 +587,33 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -517,8 +621,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -554,7 +658,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -565,29 +669,33 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -595,8 +703,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -635,7 +743,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -646,29 +754,34 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -679,8 +792,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -715,7 +828,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -726,25 +839,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { @@ -753,8 +870,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -795,7 +912,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -806,25 +923,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -837,12 +958,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -878,7 +999,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -889,43 +1010,47 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/string", - "version": "v7.0.7", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" + "reference": "758b372d6882506821ed666032e43020c4f57194" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194", + "reference": "758b372d6882506821ed666032e43020c4f57194", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -964,7 +1089,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.7" + "source": "https://github.com/symfony/string/tree/v8.0.4" }, "funding": [ { @@ -975,35 +1100,39 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.1", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", + "graham-campbell/result-type": "^1.1.4", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -1052,7 +1181,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -1064,2922 +1193,18 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:52:34+00:00" - } - ], - "packages-dev": [ - { - "name": "brianium/paratest", - "version": "v7.4.3", - "source": { - "type": "git", - "url": "https://github.com/paratestphp/paratest.git", - "reference": "64fcfd0e28a6b8078a19dbf9127be2ee645b92ec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/64fcfd0e28a6b8078a19dbf9127be2ee645b92ec", - "reference": "64fcfd0e28a6b8078a19dbf9127be2ee645b92ec", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-simplexml": "*", - "fidry/cpu-core-counter": "^1.1.0", - "jean85/pretty-package-versions": "^2.0.5", - "php": "~8.2.0 || ~8.3.0", - "phpunit/php-code-coverage": "^10.1.11 || ^11.0.0", - "phpunit/php-file-iterator": "^4.1.0 || ^5.0.0", - "phpunit/php-timer": "^6.0.0 || ^7.0.0", - "phpunit/phpunit": "^10.5.9 || ^11.0.3", - "sebastian/environment": "^6.0.1 || ^7.0.0", - "symfony/console": "^6.4.3 || ^7.0.3", - "symfony/process": "^6.4.3 || ^7.0.3" - }, - "require-dev": { - "doctrine/coding-standard": "^12.0.0", - "ext-pcov": "*", - "ext-posix": "*", - "phpstan/phpstan": "^1.10.58", - "phpstan/phpstan-deprecation-rules": "^1.1.4", - "phpstan/phpstan-phpunit": "^1.3.15", - "phpstan/phpstan-strict-rules": "^1.5.2", - "squizlabs/php_codesniffer": "^3.9.0", - "symfony/filesystem": "^6.4.3 || ^7.0.3" - }, - "bin": [ - "bin/paratest", - "bin/paratest.bat", - "bin/paratest_for_phpstorm" - ], - "type": "library", - "autoload": { - "psr-4": { - "ParaTest\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Brian Scaturro", - "email": "scaturrob@gmail.com", - "role": "Developer" - }, - { - "name": "Filippo Tessarotto", - "email": "zoeslam@gmail.com", - "role": "Developer" - } - ], - "description": "Parallel testing for PHP", - "homepage": "https://github.com/paratestphp/paratest", - "keywords": [ - "concurrent", - "parallel", - "phpunit", - "testing" - ], - "support": { - "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.4.3" - }, - "funding": [ - { - "url": "https://github.com/sponsors/Slamdunk", - "type": "github" - }, - { - "url": "https://paypal.me/filippotessarotto", - "type": "paypal" - } - ], - "time": "2024-02-20T07:24:02+00:00" - }, - { - "name": "doctrine/deprecations", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.3" - }, - "time": "2024-01-30T19:34:25+00:00" - }, - { - "name": "fidry/cpu-core-counter", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "fidry/makefile": "^0.2.0", - "fidry/php-cs-fixer-config": "^1.1.2", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", - "phpunit/phpunit": "^8.5.31 || ^9.5.26", - "webmozarts/strict-phpunit": "^7.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Fidry\\CpuCoreCounter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Théo FIDRY", - "email": "theo.fidry@gmail.com" - } - ], - "description": "Tiny utility to get the number of CPU cores.", - "keywords": [ - "CPU", - "core" - ], - "support": { - "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" - }, - "funding": [ - { - "url": "https://github.com/theofidry", - "type": "github" - } - ], - "time": "2024-02-07T09:43:46+00:00" - }, - { - "name": "filp/whoops", - "version": "2.15.4", - "source": { - "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546", - "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546", - "shasum": "" - }, - "require": { - "php": "^5.5.9 || ^7.0 || ^8.0", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" - }, - "require-dev": { - "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" - }, - "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Whoops\\": "src/Whoops/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" - } - ], - "description": "php error handling for cool kids", - "homepage": "https://filp.github.io/whoops/", - "keywords": [ - "error", - "exception", - "handling", - "library", - "throwable", - "whoops" - ], - "support": { - "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.15.4" - }, - "funding": [ - { - "url": "https://github.com/denis-sokolov", - "type": "github" - } - ], - "time": "2023-11-03T12:00:00+00:00" - }, - { - "name": "jean85/pretty-package-versions", - "version": "2.0.6", - "source": { - "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.0.0", - "php": "^7.1|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^7.5|^8.5|^9.4", - "vimeo/psalm": "^4.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Jean85\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" - } - ], - "description": "A library to get pretty versions strings of installed dependencies", - "keywords": [ - "composer", - "package", - "release", - "versions" - ], - "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.6" - }, - "time": "2024-03-08T09:58:59+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.11.1", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "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", - "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.11.1" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2023-03-08T13:26:56+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v5.0.2", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", - "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^7.0 || ^8.0 || ^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.0.2" - }, - "time": "2024-03-05T20:51:40+00:00" - }, - { - "name": "nunomaduro/collision", - "version": "v8.1.1", - "source": { - "type": "git", - "url": "https://github.com/nunomaduro/collision.git", - "reference": "13e5d538b95a744d85f447a321ce10adb28e9af9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/13e5d538b95a744d85f447a321ce10adb28e9af9", - "reference": "13e5d538b95a744d85f447a321ce10adb28e9af9", - "shasum": "" - }, - "require": { - "filp/whoops": "^2.15.4", - "nunomaduro/termwind": "^2.0.1", - "php": "^8.2.0", - "symfony/console": "^7.0.4" - }, - "conflict": { - "laravel/framework": "<11.0.0 || >=12.0.0", - "phpunit/phpunit": "<10.5.1 || >=12.0.0" - }, - "require-dev": { - "larastan/larastan": "^2.9.2", - "laravel/framework": "^11.0.0", - "laravel/pint": "^1.14.0", - "laravel/sail": "^1.28.2", - "laravel/sanctum": "^4.0.0", - "laravel/tinker": "^2.9.0", - "orchestra/testbench-core": "^9.0.0", - "pestphp/pest": "^2.34.1 || ^3.0.0", - "sebastian/environment": "^6.0.1 || ^7.0.0" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" - ] - }, - "branch-alias": { - "dev-8.x": "8.x-dev" - } - }, - "autoload": { - "files": [ - "./src/Adapters/Phpunit/Autoload.php" - ], - "psr-4": { - "NunoMaduro\\Collision\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "Cli error handling for console/command-line PHP applications.", - "keywords": [ - "artisan", - "cli", - "command-line", - "console", - "error", - "handling", - "laravel", - "laravel-zero", - "php", - "symfony" - ], - "support": { - "issues": "https://github.com/nunomaduro/collision/issues", - "source": "https://github.com/nunomaduro/collision" - }, - "funding": [ - { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" - } - ], - "time": "2024-03-06T16:20:09+00:00" - }, - { - "name": "nunomaduro/termwind", - "version": "v2.0.1", - "source": { - "type": "git", - "url": "https://github.com/nunomaduro/termwind.git", - "reference": "58c4c58cf23df7f498daeb97092e34f5259feb6a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/58c4c58cf23df7f498daeb97092e34f5259feb6a", - "reference": "58c4c58cf23df7f498daeb97092e34f5259feb6a", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^8.2", - "symfony/console": "^7.0.4" - }, - "require-dev": { - "ergebnis/phpstan-rules": "^2.2.0", - "illuminate/console": "^11.0.0", - "laravel/pint": "^1.14.0", - "mockery/mockery": "^1.6.7", - "pestphp/pest": "^2.34.1", - "phpstan/phpstan": "^1.10.59", - "phpstan/phpstan-strict-rules": "^1.5.2", - "symfony/var-dumper": "^7.0.4", - "thecodingmachine/phpstan-strict-rules": "^1.0.0" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Termwind\\Laravel\\TermwindServiceProvider" - ] - }, - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "files": [ - "src/Functions.php" - ], - "psr-4": { - "Termwind\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "Its like Tailwind CSS, but for the console.", - "keywords": [ - "cli", - "console", - "css", - "package", - "php", - "style" - ], - "support": { - "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.0.1" - }, - "funding": [ - { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://github.com/xiCO2k", - "type": "github" - } - ], - "time": "2024-03-06T16:17:14+00:00" - }, - { - "name": "pestphp/pest", - "version": "v2.34.7", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest.git", - "reference": "a7a3e4240e341d0fee1c54814ce18adc26ce5a76" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/a7a3e4240e341d0fee1c54814ce18adc26ce5a76", - "reference": "a7a3e4240e341d0fee1c54814ce18adc26ce5a76", - "shasum": "" - }, - "require": { - "brianium/paratest": "^7.3.1", - "nunomaduro/collision": "^7.10.0|^8.1.1", - "nunomaduro/termwind": "^1.15.1|^2.0.1", - "pestphp/pest-plugin": "^2.1.1", - "pestphp/pest-plugin-arch": "^2.7.0", - "php": "^8.1.0", - "phpunit/phpunit": "^10.5.17" - }, - "conflict": { - "phpunit/phpunit": ">10.5.17", - "sebastian/exporter": "<5.1.0", - "webmozart/assert": "<1.11.0" - }, - "require-dev": { - "pestphp/pest-dev-tools": "^2.16.0", - "pestphp/pest-plugin-type-coverage": "^2.8.1", - "symfony/process": "^6.4.0|^7.0.4" - }, - "bin": [ - "bin/pest" - ], - "type": "library", - "extra": { - "pest": { - "plugins": [ - "Pest\\Plugins\\Bail", - "Pest\\Plugins\\Cache", - "Pest\\Plugins\\Coverage", - "Pest\\Plugins\\Init", - "Pest\\Plugins\\Environment", - "Pest\\Plugins\\Help", - "Pest\\Plugins\\Memory", - "Pest\\Plugins\\Only", - "Pest\\Plugins\\Printer", - "Pest\\Plugins\\ProcessIsolation", - "Pest\\Plugins\\Profile", - "Pest\\Plugins\\Retry", - "Pest\\Plugins\\Snapshot", - "Pest\\Plugins\\Verbose", - "Pest\\Plugins\\Version", - "Pest\\Plugins\\Parallel" - ] - }, - "phpstan": { - "includes": [ - "extension.neon" - ] - } - }, - "autoload": { - "files": [ - "src/Functions.php", - "src/Pest.php" - ], - "psr-4": { - "Pest\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "The elegant PHP Testing Framework.", - "keywords": [ - "framework", - "pest", - "php", - "test", - "testing", - "unit" - ], - "support": { - "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.34.7" - }, - "funding": [ - { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - } - ], - "time": "2024-04-05T07:44:17+00:00" - }, - { - "name": "pestphp/pest-plugin", - "version": "v2.1.1", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest-plugin.git", - "reference": "e05d2859e08c2567ee38ce8b005d044e72648c0b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/e05d2859e08c2567ee38ce8b005d044e72648c0b", - "reference": "e05d2859e08c2567ee38ce8b005d044e72648c0b", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.0.0", - "composer-runtime-api": "^2.2.2", - "php": "^8.1" - }, - "conflict": { - "pestphp/pest": "<2.2.3" - }, - "require-dev": { - "composer/composer": "^2.5.8", - "pestphp/pest": "^2.16.0", - "pestphp/pest-dev-tools": "^2.16.0" - }, - "type": "composer-plugin", - "extra": { - "class": "Pest\\Plugin\\Manager" - }, - "autoload": { - "psr-4": { - "Pest\\Plugin\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The Pest plugin manager", - "keywords": [ - "framework", - "manager", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" - ], - "support": { - "source": "https://github.com/pestphp/pest-plugin/tree/v2.1.1" - }, - "funding": [ - { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" - } - ], - "time": "2023-08-22T08:40:06+00:00" - }, - { - "name": "pestphp/pest-plugin-arch", - "version": "v2.7.0", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest-plugin-arch.git", - "reference": "d23b2d7498475354522c3818c42ef355dca3fcda" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/d23b2d7498475354522c3818c42ef355dca3fcda", - "reference": "d23b2d7498475354522c3818c42ef355dca3fcda", - "shasum": "" - }, - "require": { - "nunomaduro/collision": "^7.10.0|^8.1.0", - "pestphp/pest-plugin": "^2.1.1", - "php": "^8.1", - "ta-tikoma/phpunit-architecture-test": "^0.8.4" - }, - "require-dev": { - "pestphp/pest": "^2.33.0", - "pestphp/pest-dev-tools": "^2.16.0" - }, - "type": "library", - "extra": { - "pest": { - "plugins": [ - "Pest\\Arch\\Plugin" - ] - } - }, - "autoload": { - "files": [ - "src/Autoload.php" - ], - "psr-4": { - "Pest\\Arch\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The Arch plugin for Pest PHP.", - "keywords": [ - "arch", - "architecture", - "framework", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" - ], - "support": { - "source": "https://github.com/pestphp/pest-plugin-arch/tree/v2.7.0" - }, - "funding": [ - { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - } - ], - "time": "2024-01-26T09:46:42+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:33:53+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "298d2febfe79d03fe714eb871d5538da55205b1a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/298d2febfe79d03fe714eb871d5538da55205b1a", - "reference": "298d2febfe79d03fe714eb871d5538da55205b1a", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.1", - "ext-filter": "*", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.5", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.0" - }, - "time": "2024-04-09T21:13:58+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.8.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "153ae662783729388a584b4361f2545e4d841e3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", - "reference": "153ae662783729388a584b4361f2545e4d841e3c", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" - }, - "time": "2024-02-23T11:10:43+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "1.29.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc", - "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0" - }, - "time": "2024-05-06T12:04:23+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "10.1.14", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-text-template": "^3.0", - "sebastian/code-unit-reverse-lookup": "^3.0", - "sebastian/complexity": "^3.0", - "sebastian/environment": "^6.0", - "sebastian/lines-of-code": "^2.0", - "sebastian/version": "^4.0", - "theseer/tokenizer": "^1.2.0" - }, - "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-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.14" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-12T15:33:41+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.17", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c1f736a473d21957ead7e94fcc029f571895abf5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1f736a473d21957ead7e94fcc029f571895abf5", - "reference": "c1f736a473d21957ead7e94fcc029f571895abf5", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", - "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.5", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-invoker": "^4.0", - "phpunit/php-text-template": "^3.0", - "phpunit/php-timer": "^6.0", - "sebastian/cli-parser": "^2.0", - "sebastian/code-unit": "^2.0", - "sebastian/comparator": "^5.0", - "sebastian/diff": "^5.0", - "sebastian/environment": "^6.0", - "sebastian/exporter": "^5.1", - "sebastian/global-state": "^6.0.1", - "sebastian/object-enumerator": "^5.0", - "sebastian/recursion-context": "^5.0", - "sebastian/type": "^4.0", - "sebastian/version": "^4.0" - }, - "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.17" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2024-04-05T04:39:01+00:00" - }, - { - "name": "psr/log", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" - }, - "time": "2021-07-14T16:46:02+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.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/diff": "^5.0", - "sebastian/exporter": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.3" - }, - "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.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-14T13:18:12+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.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "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.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:17:12+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.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "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" - }, - { - "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", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:05:40+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": "symfony/finder", - "version": "v7.0.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "4d58f0f4fe95a30d7b538d71197135483560b97c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/4d58f0f4fe95a30d7b538d71197135483560b97c", - "reference": "4d58f0f4fe95a30d7b538d71197135483560b97c", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "symfony/filesystem": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/finder/tree/v7.0.7" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-04-28T11:44:19+00:00" - }, - { - "name": "symfony/process", - "version": "v7.0.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3839e56b94dd1dbd13235d27504e66baf23faba0", - "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v7.0.7" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-04-18T09:29:19+00:00" - }, - { - "name": "ta-tikoma/phpunit-architecture-test", - "version": "0.8.4", - "source": { - "type": "git", - "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", - "reference": "89f0dea1cb0f0d5744d3ec1764a286af5e006636" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/89f0dea1cb0f0d5744d3ec1764a286af5e006636", - "reference": "89f0dea1cb0f0d5744d3ec1764a286af5e006636", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18.0 || ^5.0.0", - "php": "^8.1.0", - "phpdocumentor/reflection-docblock": "^5.3.0", - "phpunit/phpunit": "^10.5.5 || ^11.0.0", - "symfony/finder": "^6.4.0 || ^7.0.0" - }, - "require-dev": { - "laravel/pint": "^1.13.7", - "phpstan/phpstan": "^1.10.52" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPUnit\\Architecture\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ni Shi", - "email": "futik0ma011@gmail.com" - }, - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "Methods for testing application architecture", - "keywords": [ - "architecture", - "phpunit", - "stucture", - "test", - "testing" - ], - "support": { - "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", - "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.4" - }, - "time": "2024-01-05T14:10:56+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:36:25+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" - }, - "time": "2022-06-03T18:03:27+00:00" + "time": "2025-12-27T19:49:13+00:00" } ], + "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.3" + "php": "^8.4" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..d95815a Binary files /dev/null and b/logo.png differ diff --git a/src/Commands/EditGame.php b/src/Commands/EditGame.php new file mode 100644 index 0000000..c751646 --- /dev/null +++ b/src/Commands/EditGame.php @@ -0,0 +1,48 @@ +addOption('directory', 'd', InputArgument::OPTIONAL, 'The directory of the game'); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int + * @throws IOException + */ + public function execute(InputInterface $input, OutputInterface $output): int + { + $output->writeln("Opening game configuration for editing...", OutputInterface::VERBOSITY_VERBOSE); + + $directory = $input->getOption('directory') ?? '.'; + + $projectConfig = new ProjectConfig($input, $output); + $projectConfig->load(); + + $editor = new Editor(name: $projectConfig->get("name"), workingDirectory: $directory); + $editor->run(); + + $output->writeln("Finished editing game configuration.", OutputInterface::VERBOSITY_VERBOSE); + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Commands/GenerateScene.php b/src/Commands/GenerateScene.php index 3c44714..4f5281a 100644 --- a/src/Commands/GenerateScene.php +++ b/src/Commands/GenerateScene.php @@ -7,22 +7,27 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; #[AsCommand( - name: 'generate:scene', - description: 'Generate a new scene', + name: 'generate:scene', + description: 'Generate a new scene', )] class GenerateScene extends Command { - public function configure(): void - { - $this->addArgument('name', InputArgument::REQUIRED, 'The name of the scene'); - } + public function configure(): void + { + $this + ->addArgument('name', InputArgument::REQUIRED, 'The name of the scene') + ->addOption('type', 't', InputArgument::OPTIONAL | InputOption::VALUE_REQUIRED, 'The type of the scene file to generate (class, meta)', 'meta') + ->addOption('as-class', null, InputArgument::OPTIONAL | InputOption::VALUE_NONE, 'Whether to generate the scene as a class file instead of a meta file'); + } - public function execute(InputInterface $input, OutputInterface $output): int - { - $sceneGenerationStrategy = new SceneFileGenerationStrategy($input, $output, $input->getArgument('name') ?? 'scene', 'scenes'); - return $sceneGenerationStrategy->generate(); - } + public function execute(InputInterface $input, OutputInterface $output): int + { + $asClass = $input->getOption('as-class') || $input->getOption('type') === 'class'; + $sceneGenerationStrategy = new SceneFileGenerationStrategy($input, $output, $input->getArgument('name') ?? 'scene', 'scenes', asMetaFile: !$asClass); + return $sceneGenerationStrategy->generate(); + } } \ No newline at end of file diff --git a/src/Commands/NewGame.php b/src/Commands/NewGame.php index c05be86..d67066b 100644 --- a/src/Commands/NewGame.php +++ b/src/Commands/NewGame.php @@ -74,6 +74,7 @@ public function execute(InputInterface $input, OutputInterface $output): int // Create project structure $this->output->writeln('Creating project structure...', OutputInterface::VERBOSITY_VERBOSE); + $this->createConfigDirectory(); $this->createLogsDirectory(); $assetsDirectory = $this->createAssetsDirectory(); $this->createAssetsScenesDirectory($assetsDirectory); @@ -165,7 +166,7 @@ private function getComposerConfiguration(string $packageName): string 'sendamaphp/engine' => '*' ], 'require-dev' => [ - 'pestphp/pest' => '^2.34', + 'pestphp/pest' => '^4.3', 'phpstan/phpstan' => '^1.10', ], 'autoload' => [ @@ -236,6 +237,15 @@ private function createProjectConfiguration(string $projectName): void $projectName = strtolower(filter_string($projectName)); $packageName = $this->getPackageName("sendama-engine/$projectName"); + $targetConfigFilename = Path::join($this->targetDirectory, 'config', 'input.php'); + // Get the config/input.php template + $sourceInputConfigFilename = Path::join(dirname(__DIR__, 2), 'templates', 'config', 'input.php'); + $inputConfigContents = file_get_contents($sourceInputConfigFilename); + $inputConfigContents = str_replace('%PACKAGE_NAME%', $packageName, $inputConfigContents); + if (false === file_put_contents($targetConfigFilename, $inputConfigContents)) { + throw new RuntimeException(sprintf('Unable to write to file "%s"', $targetConfigFilename)); + } + $targetConfigFilename = Path::join($this->targetDirectory, 'composer.json'); if (false === file_put_contents($targetConfigFilename, $this->getComposerConfiguration($packageName))) { throw new RuntimeException(sprintf('Unable to write to file "%s"', $targetConfigFilename)); @@ -430,6 +440,23 @@ private function createLogsDirectory(): void } } + /** + * Create the config directory. + * @return void + */ + private function createConfigDirectory(): void + { + $configDirectory = Path::join($this->targetDirectory, 'config'); + if (file_exists($configDirectory)) { + $this->output->writeln('Config directory already exists...', OutputInterface::VERBOSITY_VERBOSE); + return; + } + + if (! mkdir($configDirectory) && ! is_dir($configDirectory)) { + throw new RuntimeException(sprintf('Directory "%s" was not created', $configDirectory)); + } + } + /** * Create the project directory. */ diff --git a/src/Debug/Debug.php b/src/Debug/Debug.php new file mode 100644 index 0000000..b96a082 --- /dev/null +++ b/src/Debug/Debug.php @@ -0,0 +1,159 @@ +getPriority() > $logLevel->getPriority()) { + return; + } + + + if (!file_exists($filename)) { + if (!is_writeable(self::getLogDirectory())) { + throw new DebugException("The directory, " . self::getLogDirectory() . ", is not writable."); + } + + if (false === $file = fopen($filename, 'w')) { + throw new DebugException("Failed to create the debug log file."); + } + fclose($file); + } + + $message = sprintf("[%s] %s - %s", date('Y-m-d H:i:s'), $prefix, $message) . PHP_EOL; + if (false === error_log($message, 3, $filename)) { + throw new DebugException("Failed to write to the debug log."); + } + } + + /** + * Logs an error message to the error log. + * + * @param string $message The message to log. + * @param string $prefix The prefix to add to the message. + * @throws RuntimeException Thrown if the error log file cannot be written to. + */ + public static function error(string $message, string $prefix = '[ERROR]'): void + { + if (self::$logLevel->getPriority() > LogLevel::ERROR->getPriority()) { + return; + } + + $filename = Path::join(self::getLogDirectory(), 'error.log'); + + if (!file_exists($filename)) { + if (!is_writeable(self::getLogDirectory())) { + throw new DebugException("The directory, " . self::getLogDirectory() . ", is not writable."); + } + + if (false === $file = fopen($filename, 'w')) { + throw new DebugException("Failed to create the error log file."); + } + + fclose($file); + } + + $message = sprintf("[%s] %s - %s", date('Y-m-d H:i:s'), $prefix, $message) . PHP_EOL; + if (false === error_log($message, 3, $filename)) { + throw new DebugException("Failed to write to the error log."); + } + } + + /** + * Logs a warning message to the warning log. + * + * @param string $message The message to log. + * @param string|null $prefix The prefix to add to the message. + */ + public static function warn(string $message, ?string $prefix = null): void + { + self::log($message, $prefix ?? '[WARN]', LogLevel::WARN); + } + + /** + * Logs an info message to the info log. + * + * @param string $message The message to log. + * @param string|null $prefix The prefix to add to the message. + */ + public static function info(string $message, ?string $prefix = null): void + { + self::log($message, $prefix ?? '[INFO]', LogLevel::INFO); + } +} \ No newline at end of file diff --git a/src/Debug/Enumerations/LogLevel.php b/src/Debug/Enumerations/LogLevel.php new file mode 100644 index 0000000..c1e41ea --- /dev/null +++ b/src/Debug/Enumerations/LogLevel.php @@ -0,0 +1,33 @@ + 0, + self::ERROR => 1, + self::WARN => 2, + self::INFO => 3, + self::DEBUG => 4, + }; + } +} diff --git a/src/Debug/Exceptions/DebugException.php b/src/Debug/Exceptions/DebugException.php new file mode 100644 index 0000000..628c98a --- /dev/null +++ b/src/Debug/Exceptions/DebugException.php @@ -0,0 +1,14 @@ +isRunning; + } + } + /** + * @var EditorState|null The current state of the editor. This is used to determine what the editor should do when it is running. + */ + protected ?EditorStateInterface $editorState = null; + /** + * @var int The number of frames that have been rendered. + */ + private int $frameCount = 0; + /** + * @var int The frame rate of the game. + */ + protected int $frameRate = 0; + /** + * @var bool Specifies whether debug mode is enabled or not. + */ + protected bool $isDebugMode { + get { + return $this->gameSettings?->isDebugMode; + } + } + /** + * @var bool Determines whether the debug info panel is visible or hidden. + */ + private bool $showDebugInfo = false; + /** + * @var Window + */ + private Window $debugWindow; + /** + * @var EditorSettings The editor settings + */ + protected EditorSettings $settings; + /** + * @var GameSettings|null The game settings. + */ + protected ?GameSettings $gameSettings = null; + /** + * @var ProjectBrowserState + */ + protected ProjectBrowserState $projectBrowserState; + /** + * @var EditState + */ + protected EditState $editState; + /** + * @var PlayState + */ + protected PlayState $playState; + /** + * @var ModalState + */ + protected ModalState $modalState; + /** + * @var SplashScreen + */ + protected SplashScreen $splashScreen; + + /** Panels */ + /** + * @var ItemList + */ + protected ItemList $panels; + protected HierarchyPanel $hierarchyPanel; + protected AssetsPanel $assetsPanel; + protected InspectorPanel $inspectorPanel; + + /** + * @param string $name + * @param string $workingDirectory + */ + public function __construct( + public string $name = 'Sendama Editor', + protected string $workingDirectory = '.' + ) + { + try { + register_shutdown_function(function () { + $this->finish(); + }); + + $this->initializeObservers(); + $this->configureErrorAndExceptionHandlers(); + $this->initializeSettings(); + $this->initializeManagers(); + $this->initializeConsole(); + $this->initializeWidgets(); + $this->initializeEditorStates(); + $this->splashScreen = new SplashScreen( + Console::cursor(), + new ConsoleOutput(), + $this->gameSettings + ); + } catch (Throwable $exception) { + $this->handleException($exception); + } + } + + /** + * Called when this editor construct is destroyed. + */ + public function __destruct() + { + $this->finish(); + } + + /** + * Sets the working directory for the editor. If the editor is currently running, it will be + * stopped and restarted after setting the working directory. + * + * @param string $directory The working directory to set for the editor. + * @return $this + * @throws IOException + */ + public function setWorkingDirectory(string $directory): self + { + $restartAfterSettingWorkingDirectory = $this->isRunning; + + if ($this->isRunning) { + $this->stop(); + } + + $this->workingDirectory = $directory; + + if ($restartAfterSettingWorkingDirectory) { + $this->start(); + } + + return $this; + } + + /** + * Starts the editor. + * + * @return void + * @throws IOException + */ + public function start(): void + { + Debug::info("Starting editor"); + + Console::saveSettings(); + + Console::setName($this->gameSettings?->name ?? "Sendama Editor | Unknown Game"); + + Console::setSize($this->gameSettings?->width, $this->gameSettings?->height); + + Console::cursor()->hide(); + + InputManager::disableEcho(); + + InputManager::enableNonBlockingMode(); + + $this->splashScreen->show(); + + $this->addObservers(Time::class); + + $this->isRunning = true; + + $this->notify(new EditorEvent(EventType::EDITOR_STARTED->value, $this)); + + Debug::info("Editor started"); + } + + /** + * @return void + * @throws IOException + */ + public function stop(): void + { + Console::reset(); + + Debug::info("Stopping editor"); + + InputManager::disableNonBlockingMode(); + + InputManager::enableEcho(); + + Console::cursor()->show(); + + $this->removeObservers(...$this->observers, ...$this->staticObservers); + + $this->isRunning = false; + + $this->notify(new EditorEvent(EventType::EDITOR_STOPPED->value, $this)); + + Debug::info("Editor stopped"); + } + + /** + * @return void + */ + public function finish(): void + { + Debug::info("Shutting down editor"); + + Console::restoreSettings(); + + if ($lastError = error_get_last()) { + $this->handleError($lastError["type"], $lastError["message"], $lastError["file"], $lastError["line"]); + } + + $this->notify(new EditorEvent(EventType::EDITOR_FINISHED->value, $this)); + + Debug::info("Editor shutdown complete"); + } + + /** + * @return void + * @throws IOException + */ + public function run(): void + { + $sleepTime =(int)(1000000 / self::FPS); + $this->start(); + $nextFrameTime = microtime(true) + 1; + $lastFrameCountSnapShot = $this->frameCount; + + Debug::info("Running editor"); + while ($this->isRunning) { + $this->handleInput(); + $this->update(); + + if ($this->isStopped) { + break; + } + + $this->render(); + + usleep($sleepTime); + + if (microtime(true) >= $nextFrameTime) { + $this->frameRate = $this->frameCount - $lastFrameCountSnapShot; + $lastFrameCountSnapShot = $this->frameCount; + $nextFrameTime = microtime(true) + 1; + } + } + } + + public function setState(EditorStateInterface $editorState): void + { + $context = new EditorStateContext( + $this->settings, + $this->gameSettings, + [ + 'hierarchy' => $this->hierarchyPanel, + 'assets' => $this->assetsPanel + ] + ); + + $this->editorState?->exit($context); + $this->editorState = $editorState; + $this->editorState->enter($context); + } + + /** + * Handle editor input + * + * @return void + */ + private function handleInput(): void + { + InputManager::handleInput(); + + $this->notify(new EditorEvent(EventType::EDITOR_INPUT_HANDLED->value, $this)); + } + + /** + * Update the editor state. + * + * @return void + */ + private function update(): void + { + $this->editorState->update(); + + foreach ($this->panels as $panel) { + $panel->update(); + } + + $this->notify(new EditorEvent(EventType::EDITOR_UPDATED->value, $this)); + } + + private function render(): void + { + $this->frameCount++; + $this->editorState->render(); + foreach ($this->panels as $panel) { + $panel->render(); + } + $this->renderDebugInfo(); + + $this->notify(new EditorEvent(EventType::EDITOR_RENDERED->value, $this)); + } + + private function renderDebugInfo(): void + { + if ($this->isDebugMode && $this->showDebugInfo) { + $content = ["FPS: $this->frameRate, Delta: " . round(Time::getDeltaTime() / 2), "Time: " . Time::getPrettyTime(ChronoUnit::SECONDS)]; + + $this->debugWindow->content = $content; + $this->debugWindow->render(); + } + } + + /** + * @return void + */ + protected function configureErrorAndExceptionHandlers(): void { + error_reporting(E_ALL); + + set_exception_handler(function (Throwable $throwable) { + $this->handleException($throwable); + }); + + set_error_handler(function ($errno, $errstr, $errfile, $errline) { + $this->handleError($errno, $errstr, $errfile, $errline); + }); + + $this->debugWindow = new Window(); + } + + /** + * Handles thrown Editor exceptions. + * + * @param Throwable $exception + * @return never + */ + private function handleException(Throwable $exception): never + { + Debug::error($exception); + + if ($this->gameSettings?->isDebugMode) { + exit($exception); + } + + exit("$exception\n"); + } + + /** + * Handles game errors. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * @return never + */ + private function handleError(int $errno, string $errstr, string $errfile, int $errline): never + { + $errorMessage = "[$errno] $errstr in $errfile on line $errline"; + Debug::error($errorMessage); + + if ($this->gameSettings?->isDebugMode) { + exit($errorMessage); + } + + exit($errno); + } + + protected function initializeConsole(): void + { + Console::init([ + "width" => $this->gameSettings?->width ?? DEFAULT_TERMINAL_WIDTH, + "height" => $this->gameSettings?->height ?? DEFAULT_TERMINAL_HEIGHT, + ]); + } + + private function initializeEditorStates(): void + { + $this->projectBrowserState = new ProjectBrowserState($this); + $this->editState = new EditState($this); + $this->playState = new PlayState($this); + $this->modalState = new ModalState($this); + + $this->setState($this->editState); + } + + /** + * @return void + * @throws SendamaConsoleException + */ + private function initializeSettings(): void + { + $this->settings = EditorSettings::loadFromDirectory($this->workingDirectory); + $this->gameSettings = GameSettings::loadFromDirectory($this->workingDirectory); + } + + /** + * @return void + */ + private function initializeManagers(): void + { + InputManager::init(); + } + + /** + * @return void + */ + private function initializeWidgets(): void + { + $this->panels = new ItemList(Widget::class); + $halfHeight = (int)(($this->settings->height - 1) / 2); + $this->hierarchyPanel = new HierarchyPanel(height: $halfHeight); + $this->assetsPanel = new AssetsPanel(position: ['x' => 1, 'y' => $halfHeight + 1], height: $halfHeight); + $centralPanelWidth = $this->settings->width - 2 - (35 * 2); + + $this->inspectorPanel = new InspectorPanel(position: ['x' => ($centralPanelWidth + 35), 'y' => 1], height: $this->settings->height - 1); + + $this->panels->add($this->hierarchyPanel); + $this->panels->add($this->assetsPanel); + $this->panels->add($this->inspectorPanel); + } +} \ No newline at end of file diff --git a/src/Editor/EditorSceneSettings.php b/src/Editor/EditorSceneSettings.php new file mode 100644 index 0000000..865b39b --- /dev/null +++ b/src/Editor/EditorSceneSettings.php @@ -0,0 +1,34 @@ +width; + } + } + + protected(set) int $height { + get { + return $this->height; + } + } + + /** + * @param EditorSceneSettings $scenes + */ + public function __construct( + public readonly EditorSceneSettings $scenes + ) + { + $terminalSize = get_max_terminal_size(); + $this->width = $terminalSize['width'] ?? DEFAULT_TERMINAL_WIDTH; + $this->height = $terminalSize['height'] ?? DEFAULT_TERMINAL_HEIGHT; + } + + /** + * @param string $workingDirectory + * @return self + * @throws SendamaConsoleException + */ + public static function loadFromDirectory(string $workingDirectory): self + { + $filename = Path::join($workingDirectory, 'sendama.json'); + + if (!file_exists($filename)) { + throw new SendamaConsoleException("$filename does not exist!"); + } + + $settingsJsonFileContents = file_get_contents($filename); + + if (false === $settingsJsonFileContents) { + throw new SendamaConsoleException("Failed to load contents of $filename"); + } + + $data = json_decode($settingsJsonFileContents, true); + + return self::fromArray($data); + } + + /** + * @param array $data + * @return self + */ + public static function fromArray(array $data): self + { + return new self(scenes: EditorSceneSettings::fromArray($data["scenes"] ?? [])); + } +} \ No newline at end of file diff --git a/src/Editor/Enumerations/ChronoUnit.php b/src/Editor/Enumerations/ChronoUnit.php new file mode 100644 index 0000000..a0675a1 --- /dev/null +++ b/src/Editor/Enumerations/ChronoUnit.php @@ -0,0 +1,74 @@ +key; + } + } + protected(set) bool $ctrlKey { + get { + return $this->ctrlKey; + } + } + + protected(set) bool $shiftKey { + get { + return $this->shiftKey; + } + } + + protected(set) bool $altKey { + get { + return $this->altKey; + } + } + + protected(set) bool $metaKey { + get { + return $this->metaKey; + } + } + + /** + * @param string $key + * @param bool $ctrlKey + * @param bool $shiftKey + * @param bool $altKey + * @param bool $metaKey + */ + public function __construct( + string $key, + bool $ctrlKey = false, + bool $shiftKey = false, + bool $altKey = false, + bool $metaKey = false, + ) + { + $this->key = $key; + $this->ctrlKey = $ctrlKey; + $this->shiftKey = $shiftKey; + $this->altKey = $altKey; + $this->metaKey = $metaKey; + + parent::__construct(EventType::KEYBOARD_INPUT->value, null, get_object_vars($this)); + } +} \ No newline at end of file diff --git a/src/Editor/ExecutionContext.php b/src/Editor/ExecutionContext.php new file mode 100644 index 0000000..6f8ca5b --- /dev/null +++ b/src/Editor/ExecutionContext.php @@ -0,0 +1,19 @@ +width = $terminalSize['width'] ?? DEFAULT_TERMINAL_WIDTH; + $this->height = $terminalSize['height'] ?? DEFAULT_TERMINAL_HEIGHT; + } + + /** + * Loads game settings from a specified directory. It looks for a 'sendama.json' file in the directory and parses its contents to create a GameSettings instance. + * + * @param string $directory The directory from which to load the game settings. It should contain a 'sendama.json' file with the appropriate structure. + * @return self + * @throws SendamaConsoleException + */ + public static function loadFromDirectory(string $directory): self + { + $settingsFile = $directory . '/sendama.json'; + + if (!file_exists($settingsFile)) { + Debug::warn("$settingsFile not found."); + return new self(name: 'Untitled Game'); + } + + $settingsJsonFileContents = file_get_contents($settingsFile); + + if (false === $settingsJsonFileContents) { + throw new SendamaConsoleException("Failed to load contents of $settingsFile"); + } + + $data = json_decode($settingsJsonFileContents, true); + + return self::fromArray($data); + } + + /** + * Creates a GameSettings instance from an associative array. + * The array should contain keys corresponding to the properties of GameSettings. + * + * @param array $data The associative array containing game settings data. + * @return self + */ + public static function fromArray(array $data): self + { + return new self( + name: $data['name'] ?? 'Untitled Game', + description: $data['description'] ?? '', + version: $data['version'] ?? '1.0.0', + mainFile: $data['main'] ?? self::DEFAULT_MAIN_FILE, + isDebugMode: $data['debug'] ?? false, + showDebugInfo: $data['showDebugInfo'] ?? false, + ); + } +} \ No newline at end of file diff --git a/src/Editor/IO/Button.php b/src/Editor/IO/Button.php new file mode 100644 index 0000000..9f0a170 --- /dev/null +++ b/src/Editor/IO/Button.php @@ -0,0 +1,63 @@ +name; + } + } + + /** + * @var KeyCode[] Positive button keys. + */ + protected(set) array $positiveKeys { + get { + return $this->positiveKeys; + } + } + + /** + * @var KeyCode[] Negative button keys. + */ + protected(set) array $negativeKeys { + get { + return $this->negativeKeys; + } + } + + /** + * @var float The value of the button give current input + */ + public float $value { + get { + return match (true) { + Input::isAnyKeyPressed($this->negativeKeys) => -1, + Input::isAnyKeyPressed($this->positiveKeys) => 1, + default => 0 + }; + } + } + + /** + * Constructs a button. + * + * @param string $name The name of this button. + * @param array $positiveKeys The positive keys for this button. + * @param array $negativeKeys The negative keys for this button. + */ + public function __construct( + string $name, + array $positiveKeys = [], + array $negativeKeys = [] + ) + { + $this->name = $name; + $this->positiveKeys = $positiveKeys; + $this->negativeKeys = $negativeKeys; + } +} \ No newline at end of file diff --git a/src/Editor/IO/Enumerations/AxisName.php b/src/Editor/IO/Enumerations/AxisName.php new file mode 100644 index 0000000..a34ef5a --- /dev/null +++ b/src/Editor/IO/Enumerations/AxisName.php @@ -0,0 +1,14 @@ + $keyCodes The key codes to check. + * @return bool Returns true if any key is pressed, false otherwise. + */ + public static function areAllKeysPressed(array $keyCodes): bool + { + return InputManager::areAllKeysPressed($keyCodes); + } + + /** + * Checks if any of the given keys are pressed. + * + * @param array $keyCodes + * @return bool Returns true if any key is pressed, false otherwise. + */ + public static function isAnyKeyPressed(array $keyCodes, bool $ignoreCase = true): bool + { + return InputManager::isAnyKeyPressed($keyCodes, $ignoreCase); + } + + /** + * Checks if any of the given keys are released. + * + * @param array $keyCodes The key codes to check. + * @return bool Returns true if any key is released, false otherwise. + */ + public static function isAnyKeyReleased(array $keyCodes): bool + { + return InputManager::isAnyKeyReleased($keyCodes); + } + + /** + * Checks if the given key is pressed. + * + * @param KeyCode $keyCode The key code to check. + * @return bool Returns true if the key is pressed, false otherwise. + */ + public static function isKeyDown(KeyCode $keyCode): bool + { + return InputManager::isKeyDown($keyCode); + } + + /** + * Checks if the given key was released. + * + * @param KeyCode $keyCode The key code to check. + * @return bool Returns true if the key was released, false otherwise. + */ + public static function isKeyUp(KeyCode $keyCode): bool + { + return InputManager::isKeyUp($keyCode); + } + + /** + * Checks if the given button is pressed. + * + * @param string $buttonName The name of the button to check. + * @return bool Returns true if the button is pressed, false otherwise. + */ + public static function isButtonDown(string $buttonName): bool + { + return InputManager::isButtonDown($buttonName); + } +} \ No newline at end of file diff --git a/src/Editor/IO/InputManager.php b/src/Editor/IO/InputManager.php new file mode 100644 index 0000000..62a60d5 --- /dev/null +++ b/src/Editor/IO/InputManager.php @@ -0,0 +1,293 @@ + KeyCode::UP->value, + "\033[B" => KeyCode::DOWN->value, + "\033[C" => KeyCode::RIGHT->value, + "\033[D" => KeyCode::LEFT->value, + "\n" => KeyCode::ENTER->value, + " " => KeyCode::SPACE->value, + "\010", "\177" => KeyCode::BACKSPACE->value, + "\t" => KeyCode::TAB->value, + "\033", "\e" => KeyCode::ESCAPE->value, + "\033[1~", "\033[7~" => KeyCode::HOME->value, + "\033[2~" => KeyCode::INSERT->value, + "\033[3~" => KeyCode::DELETE->value, + "\033[8", "\033[4~" => KeyCode::END->value, + "\033[5~" => KeyCode::PAGE_UP->value, + "\033[6~" => KeyCode::PAGE_DOWN->value, + "\033[10~" => KeyCode::F0->value, + "\033[11~" => KeyCode::F1->value, + "\033[12~" => KeyCode::F2->value, + "\033[13~" => KeyCode::F3->value, + "\033[14~" => KeyCode::F4->value, + "\033[15~" => KeyCode::F5->value, + "\033[17~" => KeyCode::F6->value, + "\033[18~" => KeyCode::F7->value, + "\033[19~" => KeyCode::F8->value, + "\033[20~" => KeyCode::F9->value, + "\033[21~" => KeyCode::F10->value, + "\033[23~" => KeyCode::F11->value, + "\033[24~" => KeyCode::F12->value, + default => $keyPress + }; + } + + public static function getAxis(AxisName|string $axisName): float + { + if (is_string($axisName)) { + /** @var ?Button $axis */ + $axis = array_filter(self::$buttons, fn(Button $button) => $button->getName() === $axisName)[0] ?? null; + if (is_null($axis)) { + return 0; + } + + return $axis->value; + } + + $value = 0; + + if ($axisName === AxisName::HORIZONTAL) { + if (self::isAnyKeyPressed([KeyCode::LEFT, KeyCode::A, KeyCode::a])) { + $value = -1; + } elseif (self::isAnyKeyPressed([KeyCode::RIGHT, KeyCode::D, KeyCode::d])) { + $value = 1; + } + } elseif ($axisName === AxisName::VERTICAL) { + if (self::isAnyKeyPressed([KeyCode::UP, KeyCode::W, KeyCode::w])) { + $value = -1; + } elseif (self::isAnyKeyPressed([KeyCode::DOWN, KeyCode::S, KeyCode::s])) { + $value = 1; + } + } + + return $value; + } + + /** + * Checks if any of the given keys is pressed this frame. + * + * @param KeyCode[] $keyCodes The key codes to check. + * @param bool $ignoreCase When true, performs a case-insensitive comparison i.e. 'q' and 'Q' will yield a match. + * @return bool Returns true if any key is pressed, false otherwise. + */ + public static function isAnyKeyPressed(array $keyCodes, bool $ignoreCase = true): bool + { + return array_any($keyCodes, fn($keyCode) => self::isKeyDown($keyCode, $ignoreCase)); + } + + /** + * Checks if a key is pressed down. + * + * @param KeyCode $keyCode The key code to check. + * @return bool Returns true if the key is pressed down, false otherwise. + */ + public static function isKeyDown(KeyCode $keyCode, bool $ignoreCase = true): bool + { + $key = self::getKey(self::$keyPress); + $previousKey = self::getKey(self::$previousKeyPress); + $keyCodeValue = $keyCode->value; + + if ($ignoreCase) { + $key = mb_strtolower($key); + $previousKey = mb_strtolower($previousKey); + $keyCodeValue = mb_strtolower($keyCode->value); + } + + return $key === $keyCodeValue && $previousKey !== $key; + } + + /** + * Checks if all keys are pressed. + * + * @param KeyCode[] $keyCodes The key codes to check. + * @return bool Returns true if all keys are pressed, false otherwise. + */ + public static function areAllKeysPressed(array $keyCodes): bool + { + return array_all($keyCodes, fn($keyCode) => self::isKeyPressed($keyCode)); + } + + /** + * Checks if a key is pressed. + * + * @param KeyCode $keyCode The key code to check. + * @return bool Returns true if the key is pressed, false otherwise. + */ + public static function isKeyPressed(KeyCode $keyCode): bool + { + return self::$keyPress === $keyCode->value; + } + + /** + * Checks if any of the given key codes was released. + * + * @param KeyCode[] $keyCodes The key codes to check. + * @return bool Returns true if any key is released, false otherwise. + */ + public static function isAnyKeyReleased(array $keyCodes): bool + { + return array_any($keyCodes, fn($keyCode) => self::isKeyUp($keyCode)); + } + + /** + * Checks if a key is released. + * + * @param KeyCode $keyCode The key code to check. + * @return bool Returns true if the key is released, false otherwise. + */ + public static function isKeyUp(KeyCode $keyCode): bool + { + $key = self::getKey(self::$keyPress); + $previousKey = self::getKey(self::$previousKeyPress); + + return empty($key) && $previousKey === $keyCode->value; + } + + /** + * Checks if a button of given name $buttonName is down. + * + * @param string $buttonName The name of the button. + * @return bool Returns true if the button is down, false otherwise. + */ + public static function isButtonDown(string $buttonName): bool + { + foreach (self::$buttons as $button) { + if ($button->getName() === $buttonName) { + return self::isAnyKeyPressed($button->getPositiveKeys()); + } + } + + return false; + } + + /** + * Adds an axis. + * + * @param VirtualAxis ...$axes The axis to add. + * @return void + */ + public static function addAxes(VirtualAxis ...$axes): void + { + foreach ($axes as $axis) { + self::$axes[] = $axis; + } + } + + /** + * Finds an axis by name. + * + * @param string $axisName The name of the axis. + * @return VirtualAxis|null Returns the axis if found, null otherwise. + * @phpstan-ignore method.unused + */ + private static function findAxis(string $axisName): ?VirtualAxis + { + return array_filter(self::$axes, fn($axis) => $axis->getName() === $axisName)[0] ?? null; + } +} \ No newline at end of file diff --git a/src/Editor/IO/VirtualAxis.php b/src/Editor/IO/VirtualAxis.php new file mode 100644 index 0000000..02b9a92 --- /dev/null +++ b/src/Editor/IO/VirtualAxis.php @@ -0,0 +1,69 @@ +name; + } + } + + /** + * @var KeyCode[] Positive axis buttons + */ + protected(set) array $positiveButtons { + get { + return $this->positiveButtons; + } + } + + /** + * @var KeyCode[] Negative axis buttons + */ + protected(set) array $negativeButtons { + get { + return $this->negativeButtons; + } + } + + /** + * @var float The value of the axis give current input + */ + public float $value { + get { + return match (true) { + Input::isAnyKeyPressed($this->negativeButtons) => -1, + Input::isAnyKeyPressed($this->positiveButtons) => 1, + default => 0 + }; + } + } + + /** + * Build a new virtual axis. + * + * @param string $name The name of this axis. + * @param KeyCode[] $positiveButtons The positive buttons for this axis. + * @param KeyCode[] $negativeButtons The negative buttons for this axis. + */ + public function __construct( + string $name, + array $positiveButtons = [], + array $negativeButtons = [] + ) + { + $this->name = $name; + $this->positiveButtons = $positiveButtons; + $this->negativeButtons = $negativeButtons; + } +} \ No newline at end of file diff --git a/src/Editor/Interfaces/EditorStateInterface.php b/src/Editor/Interfaces/EditorStateInterface.php new file mode 100644 index 0000000..ff15bfe --- /dev/null +++ b/src/Editor/Interfaces/EditorStateInterface.php @@ -0,0 +1,49 @@ +settings->width; + $terminalHeight = $this->settings->height; + + $imageRows = explode("\n", $image); + $imageWidth = array_reduce($imageRows, function (?string $a, ?string $b): int { + if (!$a) { + return strlen($b ?? ''); + } + + if (!$b) { + return strlen($a); + } + + $lengthA = strlen($a); + $lengthB = strlen($b); + return ($lengthA > $lengthB) ? $lengthA : $lengthB; + }); + $imageHeight = count($imageRows); + + $leftMargin = max(0, (($terminalWidth / 2) - ($imageWidth / 2))); + $topMargin = max(0, (($terminalHeight / 2) - ($imageHeight / 2))); + + foreach ($imageRows as $index => $imageRow) { + $this->cursor->moveTo((int)$leftMargin, (int)($topMargin + $index)); + $this->output->write($imageRow); + } + + $duration = (int)(self::SPLASH_SCREEN_DURATION * 1000000); + usleep($duration); + + Console::clear(); + } +} \ No newline at end of file diff --git a/src/Editor/States/EditState.php b/src/Editor/States/EditState.php new file mode 100644 index 0000000..dbee754 --- /dev/null +++ b/src/Editor/States/EditState.php @@ -0,0 +1,31 @@ +editor->stop(); + } + } + + /** + * @inheritDoc + */ + public function render(): void + { + // TODO: Implement render() method. + } +} \ No newline at end of file diff --git a/src/Editor/States/EditorState.php b/src/Editor/States/EditorState.php new file mode 100644 index 0000000..e97cab2 --- /dev/null +++ b/src/Editor/States/EditorState.php @@ -0,0 +1,53 @@ +editor->setState($state); + } +} \ No newline at end of file diff --git a/src/Editor/States/EditorStateContext.php b/src/Editor/States/EditorStateContext.php new file mode 100644 index 0000000..86cd141 --- /dev/null +++ b/src/Editor/States/EditorStateContext.php @@ -0,0 +1,28 @@ +cursor = Console::cursor(); + } +} \ No newline at end of file diff --git a/src/Editor/States/ModalState.php b/src/Editor/States/ModalState.php new file mode 100644 index 0000000..fbbd804 --- /dev/null +++ b/src/Editor/States/ModalState.php @@ -0,0 +1,25 @@ + hrtime(true), + ChronoUnit::MILLIS => microtime(true) * 1000, + ChronoUnit::MICROS => microtime(true), + ChronoUnit::SECONDS => time(), + default => throw new InvalidArgumentException('Invalid ChronoUnit.'), + }; + } + + /** + * Gets the time since the start of the game. + * + * @return float The time since the start of the game. + */ + public static function getTime(): float + { + return self::$time; + } + + /** + * Returns the timescale of the game. + * + * @return float The timescale of the game. + */ + public static function getTimeScale(): float + { + return self::$timeScale; + } + + /** + * Sets the timescale of the game. + * + * @param float $timeScale The timescale of the game. + * @return void + */ + public static function setTimeScale(float $timeScale): void + { + self::$timeScale = clamp($timeScale, 0.0, 1.0); + } + + /** + * Called when the game is updated. + * + * @return void + */ + public static function onEditorUpdate(): void + { + self::$time = self::getSystemTime() - self::$startTime; + self::$deltaTime = self::getTime() - self::$lastTime; + self::$lastTime = self::getTime(); + self::$frames++; + } + + /** + * Gets the time since the last frame in nanoseconds. + * + * @return float The time since the last frame in nanoseconds. + */ + public static function getDeltaTime(): float + { + return self::$deltaTime; + } + + /** + * Returns a formatted string of the time since the game started. + * + * @param ChronoUnit $chronoUnit The unit of time to return. + * @return string A formatted string of the time since the game started. + */ + public static function getPrettyTime(ChronoUnit $chronoUnit = ChronoUnit::MINUTES): string + { + $time = (int)self::$time; + $hours = floor($time / 3600); + $minutes = floor((int)($time / 60) % 60); + $seconds = $time % 60; + + if ($chronoUnit === ChronoUnit::MINUTES) + { + $days = floor($hours / 24); + return sprintf('%02d:%02d:%02d', $days, $hours, $minutes); + } + + return sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds); + } + + /** + * @inheritDoc + */ + public static function onNotify(ObservableInterface|null $observable, Event $event): void + { + switch ($event->type) + { + case EventType::EDITOR_STARTED->value: + self::onEditorStart(); + break; + + case EventType::EDITOR_STOPPED->value: + self::onEditorStop(); + break; + + case EventType::EDITOR_FINISHED->value: + self::onEditorFinished(); + break; + + case EventType::EDITOR_UPDATED->value: + self::onEditorUpdate(); + break; + + case EventType::EDITOR_RENDERED->value: + self::onEditorRender(); + break; + + case EventType::EDITOR_STATE_CHANGED->value: + self::onEditorStateChange(); + break; + } + } + + /** + * Called when the editor is stopped. + * + * @return void + */ + private static function onEditorStop(): void + { + self::$stopTime = self::getSystemTime(); + } + + /** + * Called when the editor is rendered. + * + * @return void + */ + private static function onEditorRender(): void + { + // TODO: Implement onEditorRender() method. + } + + /** + * Called when the editor is finished. + * + * @return void + */ + private static function onEditorFinished(): void + { + // TODO: Implement onEditorFinished() method. + } + + /** + * Called when the editor is finished. + * + * @return void + */ + private static function onEditorStateChange(): void + { + // TODO: Implement onEditorStateChange() method. + } +} \ No newline at end of file diff --git a/src/Editor/Widgets/AssetsPanel.php b/src/Editor/Widgets/AssetsPanel.php new file mode 100644 index 0000000..c833b54 --- /dev/null +++ b/src/Editor/Widgets/AssetsPanel.php @@ -0,0 +1,23 @@ + 1, 'y' => 15], + int $width = 35, + int $height = 14 + ) + { + parent::__construct('Assets', '', $position, $width, $height); + } + + /** + * @inheritDoc + */ + public function update(): void + { + // TODO: Implement update() method. + } +} \ No newline at end of file diff --git a/src/Editor/Widgets/HierarchyPanel.php b/src/Editor/Widgets/HierarchyPanel.php new file mode 100644 index 0000000..e86e568 --- /dev/null +++ b/src/Editor/Widgets/HierarchyPanel.php @@ -0,0 +1,26 @@ + 1, 'y' => 1], + int $width = 35, + int $height = 14 + ) + { + parent::__construct('Hierarchy', '', $position, $width, $height); + } + + /** + * @inheritDoc + */ + public function update(): void + { + // TODO: Implement update() method. + } +} \ No newline at end of file diff --git a/src/Editor/Widgets/InspectorPanel.php b/src/Editor/Widgets/InspectorPanel.php new file mode 100644 index 0000000..81923e4 --- /dev/null +++ b/src/Editor/Widgets/InspectorPanel.php @@ -0,0 +1,25 @@ + 135, 'y' => 1], + int $width = 35, + int $height = 29 + ) + { + parent::__construct('Inspector', '', $position, $width, $height); + } + + /** + * @inheritDoc + */ + public function update(): void + { + // TODO: Implement update() method. + } +} \ No newline at end of file diff --git a/src/Editor/Widgets/Widget.php b/src/Editor/Widgets/Widget.php new file mode 100644 index 0000000..72b0fac --- /dev/null +++ b/src/Editor/Widgets/Widget.php @@ -0,0 +1,80 @@ +position["x"] ?? 0; + } + + set { + $this->position["y"] = $value; + } + } + /** + * @var int + */ + public int $y { + get { + return $this->position["y"] ?? 0; + } + + set { + $this->position["y"] = $value; + } + } + protected(set) bool $isEnabled = true; + + /** + * Enables the widget. + * + * @return void + */ + public function enable(): void + { + $this->isEnabled = true; + } + + /** + * Disables the widget. + * + * @return void + */ + public function disable(): void + { + $this->isEnabled = false; + } + + /** + * @inheritDoc + */ + public function focus(FocusTargetContext $context): void + { + // TODO: Implement focus() method. + } + + /** + * @inheritDoc + */ + public function blur(FocusTargetContext $context): void + { + // TODO: Implement blur() method. + } + + /** + * @return void + */ + public abstract function update(): void; +} \ No newline at end of file diff --git a/src/Exceptions/IOException.php b/src/Exceptions/IOException.php new file mode 100644 index 0000000..79b7300 --- /dev/null +++ b/src/Exceptions/IOException.php @@ -0,0 +1,12 @@ +projectConfig = new ProjectConfig($input, $output); - $this->composerConfig = new ComposerConfig($input, $output); - $this->inspector = new Inspector($input, $output); - - $nameTokens = explode('/', $this->filename); - - $this->classPath = to_pascal_case($this->directory); - - foreach ($nameTokens as $token) { - $this->classPath = Path::join($this->classPath, to_pascal_case($token)); + /** + * The class path. + * + * @var string + */ + protected string $content = ''; + /** + * @var ProjectConfig + */ + protected ProjectConfig $projectConfig; + /** + * @var ComposerConfig + */ + protected ComposerConfig $composerConfig; + /** + * @var Inspector + */ + protected Inspector $inspector; + protected string $classPath = ''; + protected string $className = ''; + protected string $relativeFilename = ''; + protected string $suffix = ''; + + /** + * AssetFileGenerationStrategy constructor. + * + * @param InputInterface $input + * @param OutputInterface $output + * @param string $filename + * @param string $directory + * @param string|null $fileExtension + */ + public function __construct( + protected InputInterface $input, + protected OutputInterface $output, + protected string $filename, + protected string $directory, + protected ?string $fileExtension = null + ) + { + $this->projectConfig = new ProjectConfig($input, $output); + $this->composerConfig = new ComposerConfig($input, $output); + $this->inspector = new Inspector($input, $output); + + $nameTokens = explode('/', $this->filename); + + $this->classPath = to_pascal_case($this->directory); + + foreach ($nameTokens as $token) { + $this->classPath = Path::join($this->classPath, to_pascal_case($token)); + } + + if ($this->suffix) { + $this->suffix = to_pascal_case($this->suffix); + $this->classPath = $this->classPath . $this->suffix; + } + + $this->className = basename($this->classPath); + + $this->relativeFilename = Path::join('assets', $this->classPath . ($this->fileExtension ?? '.php')); + + $this->configure(); } - if ($this->suffix) { - $this->suffix = to_pascal_case($this->suffix); - $this->classPath = $this->classPath . $this->suffix; + /** + * Configure the asset file generation strategy. + */ + protected abstract function configure(): void; + + /** + * @inheritDoc + */ + public function generate(): int + { + $this->inspector->validateProjectDirectory(); + + $filename = Path::join(getcwd() ?: '', $this->relativeFilename); + + if (!file_exists(dirname($filename))) { + if (false === mkdir(dirname($filename), 0777, true)) { + $this->output->writeln("Failed to create directory " . dirname($filename) . "."); + return Command::FAILURE; + } + } + + if (file_exists($filename)) { + $this->output->writeln("$this->relativeFilename already exists."); + return Command::FAILURE; + } + + $bytes = file_put_contents($filename, $this->content); + + if (false === $bytes) { + $this->output->writeln("Failed to generate script $filename."); + return Command::FAILURE; + } + + $this->output->writeln("CREATE $this->relativeFilename ($bytes bytes)"); + return Command::SUCCESS; } - - $this->className = basename($this->classPath); - - $this->relativeFilename = Path::join('assets', $this->classPath . ($this->fileExtension ?? '.php')); - - $this->configure(); - } - - /** - * Configure the asset file generation strategy. - */ - protected abstract function configure(): void; - - /** - * @inheritDoc - */ - public function generate(): int - { - $this->inspector->validateProjectDirectory(); - - $filename = Path::join(getcwd() ?: '', $this->relativeFilename); - - if (! file_exists(dirname($filename)) ) { - if (false === mkdir(dirname($filename), 0777, true)) { - $this->output->writeln("Failed to create directory " . dirname($filename) . "."); - return Command::FAILURE; - } - } - - if ( file_exists($filename) ) { - $this->output->writeln("$this->relativeFilename already exists."); - return Command::FAILURE; - } - - $bytes = file_put_contents($filename, $this->content); - - if (false === $bytes) { - $this->output->writeln("Failed to generate script $filename."); - return Command::FAILURE; - } - - $this->output->writeln("CREATE $this->relativeFilename ($bytes bytes)"); - return Command::SUCCESS; - } } \ No newline at end of file diff --git a/src/Strategies/AssetFileGeneration/SceneFileGenerationStrategy.php b/src/Strategies/AssetFileGeneration/SceneFileGenerationStrategy.php index 47091c5..d217adb 100644 --- a/src/Strategies/AssetFileGeneration/SceneFileGenerationStrategy.php +++ b/src/Strategies/AssetFileGeneration/SceneFileGenerationStrategy.php @@ -2,15 +2,71 @@ namespace Sendama\Console\Strategies\AssetFileGeneration; +use Sendama\Console\Util\Path; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + class SceneFileGenerationStrategy extends AbstractAssetFileGenerationStrategy { + public function __construct( + InputInterface $input, + OutputInterface $output, + string $filename, + string $directory, + ?string $fileExtension = null, + protected bool $asMetaFile = true + ) + { + if ($this->asMetaFile) { + $fileExtension = '.scene.php'; + } - /** - * @inheritDoc - */ - protected function configure(): void - { - $this->content = <<asMetaFile) { + $filename = Path::join(dirname($this->classPath), to_kebab_case($this->className)); + $this->relativeFilename = Path::join('assets', $filename . ($this->fileExtension ?? '.php')); + $this->content = << DEFAULT_SCREEN_WIDTH, + "height" => DEFAULT_SCREEN_HEIGHT, + "environmentTileMapPath" => "Maps/example", + "hierarchy" => [ + [ + "type" => GameObject::class, + "name" => "Level Manager", + "position" => [0, 0], + "rotation" => [0, 0], + "scale" => [1, 1], + "components" => [ + [ "class" => SimpleQuitListener::class ], + ] + ], + [ + "type" => GameObject::class, + "name" => "GameObject", + "position" => [1, 1], + "rotation" => [0, 0], + "scale" => [1, 1], + "components" => [] + ] + ], +]; + +PHP; + } else { + $this->content = <<composerConfig->getNamespace()}Scenes; @@ -29,7 +85,7 @@ public function awake(): void // create your game objects here \$levelManager = new GameObject('Level Manager'); - \$myGameObject = new GameObject('My Game Object', position: Vector2::one()); + \$myGameObject = new GameObject('GameObject', position: Vector2::one()); // TODO: Add components to the GameObject \$levelManager->addComponent(SimpleQuitListener::class); @@ -41,5 +97,6 @@ public function awake(): void } PHP; - } + } + } } \ No newline at end of file diff --git a/src/Util/Functions.php b/src/Util/Functions.php index bd60fcc..8655804 100644 --- a/src/Util/Functions.php +++ b/src/Util/Functions.php @@ -207,4 +207,11 @@ function write_console_error(string|array $messages, OutputInterface $output = n { write_console_log($messages, $output, 'error'); } +} + +if (! function_exists('clamp') ) { + function clamp(float $value, float $min, float $max): float + { + return max($min, min($max, $value)); + } } \ No newline at end of file