diff --git a/composer.json b/composer.json index e788b01..b79b4d7 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "php": ">=8.1", "composer/semver": "^3.4", "internal/destroy": "^1.0", + "internal/toml": "^1.0.2", "nyholm/psr7": "^1.8", "psr/container": "1 - 2", "psr/http-client": "^1.0", diff --git a/composer.lock b/composer.lock index 593b45c..d8c3792 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": "e81ea9ce2b108cd3984a90d1a3e187a4", + "content-hash": "bd4f50e500e483c3348384632515f984", "packages": [ { "name": "composer/semver", @@ -142,6 +142,62 @@ ], "time": "2025-09-08T14:29:16+00:00" }, + { + "name": "internal/toml", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-internal/toml.git", + "reference": "b3aad5704a4d5ca15629566d87f880cd20426c41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-internal/toml/zipball/b3aad5704a4d5ca15629566d87f880cd20426c41", + "reference": "b3aad5704a4d5ca15629566d87f880cd20426c41", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "buggregator/trap": "^1.13", + "phpunit/phpunit": "^10.5", + "spiral/code-style": "^2.3.0", + "ta-tikoma/phpunit-architecture-test": "^0.8.5", + "vimeo/psalm": "^6.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "Internal\\Toml\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Aleksei Gagarin (roxblnfk)", + "homepage": "https://github.com/roxblnfk" + } + ], + "description": "TOML support for PHP", + "keywords": [ + "toml" + ], + "support": { + "issues": "https://github.com/php-internal/toml/issues", + "source": "https://github.com/php-internal/toml/tree/1.0.2" + }, + "funding": [ + { + "url": "https://patreon.com/roxblnfk", + "type": "patreon" + } + ], + "time": "2025-11-06T16:32:02+00:00" + }, { "name": "nyholm/psr7", "version": "1.8.2", @@ -705,16 +761,16 @@ }, { "name": "symfony/console", - "version": "v6.4.25", + "version": "v6.4.27", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae" + "reference": "13d3176cf8ad8ced24202844e9f95af11e2959fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "url": "https://api.github.com/repos/symfony/console/zipball/13d3176cf8ad8ced24202844e9f95af11e2959fc", + "reference": "13d3176cf8ad8ced24202844e9f95af11e2959fc", "shasum": "" }, "require": { @@ -779,7 +835,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.25" + "source": "https://github.com/symfony/console/tree/v6.4.27" }, "funding": [ { @@ -799,7 +855,7 @@ "type": "tidelift" } ], - "time": "2025-08-22T10:21:53+00:00" + "time": "2025-10-06T10:25:16+00:00" }, { "name": "symfony/deprecation-contracts", @@ -870,16 +926,16 @@ }, { "name": "symfony/http-client", - "version": "v6.4.25", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "b8e9dce2d8acba3c32af467bb58e0c3656886181" + "reference": "6740cdc1a3bffa127966b6056e883b3fe3709849" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/b8e9dce2d8acba3c32af467bb58e0c3656886181", - "reference": "b8e9dce2d8acba3c32af467bb58e0c3656886181", + "url": "https://api.github.com/repos/symfony/http-client/zipball/6740cdc1a3bffa127966b6056e883b3fe3709849", + "reference": "6740cdc1a3bffa127966b6056e883b3fe3709849", "shasum": "" }, "require": { @@ -944,7 +1000,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.25" + "source": "https://github.com/symfony/http-client/tree/v6.4.26" }, "funding": [ { @@ -964,7 +1020,7 @@ "type": "tidelift" } ], - "time": "2025-08-27T07:01:16+00:00" + "time": "2025-09-11T09:57:09+00:00" }, { "name": "symfony/http-client-contracts", @@ -1544,16 +1600,16 @@ }, { "name": "symfony/string", - "version": "v6.4.25", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1" + "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "url": "https://api.github.com/repos/symfony/string/zipball/5621f039a71a11c87c106c1c598bdcd04a19aeea", + "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea", "shasum": "" }, "require": { @@ -1567,7 +1623,6 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0|^7.0", "symfony/http-client": "^5.4|^6.0|^7.0", "symfony/intl": "^6.2|^7.0", "symfony/translation-contracts": "^2.5|^3.0", @@ -1610,7 +1665,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.25" + "source": "https://github.com/symfony/string/tree/v6.4.26" }, "funding": [ { @@ -1630,7 +1685,7 @@ "type": "tidelift" } ], - "time": "2025-08-22T12:33:20+00:00" + "time": "2025-09-11T14:32:46+00:00" }, { "name": "yiisoft/injector", @@ -2016,16 +2071,16 @@ }, { "name": "amphp/parallel", - "version": "v2.3.1", + "version": "v2.3.2", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "5113111de02796a782f5d90767455e7391cca190" + "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/5113111de02796a782f5d90767455e7391cca190", - "reference": "5113111de02796a782f5d90767455e7391cca190", + "url": "https://api.github.com/repos/amphp/parallel/zipball/321b45ae771d9c33a068186b24117e3cd1c48dce", + "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce", "shasum": "" }, "require": { @@ -2088,7 +2143,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.3.1" + "source": "https://github.com/amphp/parallel/tree/v2.3.2" }, "funding": [ { @@ -2096,7 +2151,7 @@ "type": "github" } ], - "time": "2024-12-21T01:56:09+00:00" + "time": "2025-08-27T21:55:40+00:00" }, { "name": "amphp/parser", @@ -2514,23 +2569,23 @@ }, { "name": "buggregator/trap", - "version": "1.13.16", + "version": "1.13.18", "source": { "type": "git", "url": "https://github.com/buggregator/trap.git", - "reference": "2c08a25c77fc5aa5cde1a3ce9b0199306a3ee49a" + "reference": "1560e7da26691baa2aace06cbd575cc9e8b06624" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/buggregator/trap/zipball/2c08a25c77fc5aa5cde1a3ce9b0199306a3ee49a", - "reference": "2c08a25c77fc5aa5cde1a3ce9b0199306a3ee49a", + "url": "https://api.github.com/repos/buggregator/trap/zipball/1560e7da26691baa2aace06cbd575cc9e8b06624", + "reference": "1560e7da26691baa2aace06cbd575cc9e8b06624", "shasum": "" }, "require": { "clue/stream-filter": "^1.6", "ext-filter": "*", "ext-sockets": "*", - "nunomaduro/termwind": "^1.15.1 || ^2", + "internal/destroy": "^1.0", "nyholm/psr7": "^1.8", "php": ">=8.1", "php-http/message": "^1.15", @@ -2600,7 +2655,7 @@ ], "support": { "issues": "https://github.com/buggregator/trap/issues", - "source": "https://github.com/buggregator/trap/tree/1.13.16" + "source": "https://github.com/buggregator/trap/tree/1.13.18" }, "funding": [ { @@ -2612,7 +2667,7 @@ "type": "patreon" } ], - "time": "2025-06-09T08:58:44+00:00" + "time": "2025-09-08T19:47:24+00:00" }, { "name": "clue/stream-filter", @@ -3517,16 +3572,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.6.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { @@ -3569,94 +3624,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" - }, - "time": "2025-08-13T20:13:15+00:00" - }, - { - "name": "nunomaduro/termwind", - "version": "v1.17.0", - "source": { - "type": "git", - "url": "https://github.com/nunomaduro/termwind.git", - "reference": "5369ef84d8142c1d87e4ec278711d4ece3cbf301" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/5369ef84d8142c1d87e4ec278711d4ece3cbf301", - "reference": "5369ef84d8142c1d87e4ec278711d4ece3cbf301", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^8.1", - "symfony/console": "^6.4.15" - }, - "require-dev": { - "illuminate/console": "^10.48.24", - "illuminate/support": "^10.48.24", - "laravel/pint": "^1.18.2", - "pestphp/pest": "^2.36.0", - "pestphp/pest-plugin-mock": "2.0.0", - "phpstan/phpstan": "^1.12.11", - "phpstan/phpstan-strict-rules": "^1.6.1", - "symfony/var-dumper": "^6.4.15", - "thecodingmachine/phpstan-strict-rules": "^1.0.0" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Termwind\\Laravel\\TermwindServiceProvider" - ] - } - }, - "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/v1.17.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" }, - "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-11-21T10:36:35+00:00" + "time": "2025-10-21T19:32:17+00:00" }, { "name": "phar-io/manifest", @@ -3778,16 +3748,16 @@ }, { "name": "php-cs-fixer/shim", - "version": "v3.86.0", + "version": "v3.89.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/shim.git", - "reference": "b43770ec215a30afff187ac273da6b43575c0ae3" + "reference": "69182624902af6b2adafb30e2a092f0e6dd89fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/b43770ec215a30afff187ac273da6b43575c0ae3", - "reference": "b43770ec215a30afff187ac273da6b43575c0ae3", + "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/69182624902af6b2adafb30e2a092f0e6dd89fab", + "reference": "69182624902af6b2adafb30e2a092f0e6dd89fab", "shasum": "" }, "require": { @@ -3824,9 +3794,9 @@ "description": "A tool to automatically fix PHP code style", "support": { "issues": "https://github.com/PHP-CS-Fixer/shim/issues", - "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.86.0" + "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.89.1" }, - "time": "2025-08-13T22:37:38+00:00" + "time": "2025-10-24T12:05:38+00:00" }, { "name": "php-http/message", @@ -4074,16 +4044,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", "shasum": "" }, "require": { @@ -4115,9 +4085,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" }, - "time": "2025-07-13T07:04:09+00:00" + "time": "2025-08-30T15:50:23+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4442,16 +4412,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.53", + "version": "10.5.58", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "32768472ebfb6969e6c7399f1c7b09009723f653" + "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/32768472ebfb6969e6c7399f1c7b09009723f653", - "reference": "32768472ebfb6969e6c7399f1c7b09009723f653", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e24fb46da450d8e6a5788670513c1af1424f16ca", + "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca", "shasum": "" }, "require": { @@ -4472,10 +4442,10 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.3", + "sebastian/comparator": "^5.0.4", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", - "sebastian/exporter": "^5.1.2", + "sebastian/exporter": "^5.1.4", "sebastian/global-state": "^6.0.2", "sebastian/object-enumerator": "^5.0.0", "sebastian/recursion-context": "^5.0.1", @@ -4523,7 +4493,7 @@ "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.53" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.58" }, "funding": [ { @@ -4547,7 +4517,7 @@ "type": "tidelift" } ], - "time": "2025-08-20T14:40:06+00:00" + "time": "2025-09-28T12:04:46+00:00" }, { "name": "revolt/event-loop", @@ -4791,16 +4761,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.3", + "version": "5.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" + "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", - "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e", + "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e", "shasum": "" }, "require": { @@ -4856,15 +4826,27 @@ "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.3" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.4" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2024-10-18T14:56:07+00:00" + "time": "2025-09-07T05:25:07+00:00" }, { "name": "sebastian/complexity", @@ -5057,16 +5039,16 @@ }, { "name": "sebastian/exporter", - "version": "5.1.2", + "version": "5.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf" + "reference": "0735b90f4da94969541dac1da743446e276defa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6", + "reference": "0735b90f4da94969541dac1da743446e276defa6", "shasum": "" }, "require": { @@ -5075,7 +5057,7 @@ "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -5123,15 +5105,27 @@ "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" + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2024-03-02T07:17:12+00:00" + "time": "2025-09-24T06:09:11+00:00" }, { "name": "sebastian/global-state", @@ -5620,16 +5614,16 @@ }, { "name": "spiral/code-style", - "version": "v2.3.0", + "version": "v2.3.1", "source": { "type": "git", "url": "https://github.com/spiral/code-style.git", - "reference": "d9742a53dbd9ae815054ba5ffc89c8cf92a774fc" + "reference": "a0407ffcb300c9d2977cb3d1c36af0d13b2ffb72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spiral/code-style/zipball/d9742a53dbd9ae815054ba5ffc89c8cf92a774fc", - "reference": "d9742a53dbd9ae815054ba5ffc89c8cf92a774fc", + "url": "https://api.github.com/repos/spiral/code-style/zipball/a0407ffcb300c9d2977cb3d1c36af0d13b2ffb72", + "reference": "a0407ffcb300c9d2977cb3d1c36af0d13b2ffb72", "shasum": "" }, "require": { @@ -5664,7 +5658,7 @@ "description": "Code style and static analysis tools rulesets collection", "homepage": "https://github.com/spiral/code-style", "support": { - "source": "https://github.com/spiral/code-style/tree/v2.3.0" + "source": "https://github.com/spiral/code-style/tree/v2.3.1" }, "funding": [ { @@ -5672,7 +5666,7 @@ "type": "github" } ], - "time": "2025-08-28T07:10:02+00:00" + "time": "2025-10-06T17:24:48+00:00" }, { "name": "symfony/filesystem", @@ -5746,16 +5740,16 @@ }, { "name": "symfony/finder", - "version": "v6.4.24", + "version": "v6.4.27", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "73089124388c8510efb8d2d1689285d285937b08" + "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/73089124388c8510efb8d2d1689285d285937b08", - "reference": "73089124388c8510efb8d2d1689285d285937b08", + "url": "https://api.github.com/repos/symfony/finder/zipball/a1b6aa435d2fba50793b994a839c32b6064f063b", + "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b", "shasum": "" }, "require": { @@ -5790,7 +5784,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.24" + "source": "https://github.com/symfony/finder/tree/v6.4.27" }, "funding": [ { @@ -5810,7 +5804,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T12:02:45+00:00" + "time": "2025-10-15T18:32:00+00:00" }, { "name": "symfony/polyfill-php84", @@ -5894,16 +5888,16 @@ }, { "name": "symfony/var-dumper", - "version": "v6.4.25", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "c6cd92486e9fc32506370822c57bc02353a5a92c" + "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c6cd92486e9fc32506370822c57bc02353a5a92c", - "reference": "c6cd92486e9fc32506370822c57bc02353a5a92c", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/cfae1497a2f1eaad78dbc0590311c599c7178d4a", + "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a", "shasum": "" }, "require": { @@ -5958,7 +5952,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.25" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.26" }, "funding": [ { @@ -5978,7 +5972,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2025-09-25T15:37:27+00:00" }, { "name": "ta-tikoma/phpunit-architecture-test", @@ -6209,28 +6203,28 @@ }, { "name": "webmozart/assert", - "version": "1.11.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", "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" + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" }, "type": "library", "extra": { @@ -6261,9 +6255,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" + "source": "https://github.com/webmozarts/assert/tree/1.12.1" }, - "time": "2022-06-03T18:03:27+00:00" + "time": "2025-10-29T15:56:20+00:00" } ], "aliases": [], diff --git a/src/Module/Velox/Internal/Config/Pipeline/Processor/BaseTemplateProcessor.php b/src/Module/Velox/Internal/Config/Pipeline/Processor/BaseTemplateProcessor.php index 9e21ea8..d837d0f 100644 --- a/src/Module/Velox/Internal/Config/Pipeline/Processor/BaseTemplateProcessor.php +++ b/src/Module/Velox/Internal/Config/Pipeline/Processor/BaseTemplateProcessor.php @@ -28,7 +28,7 @@ public function __invoke(ConfigContext $context): ConfigContext 'mode' => 'dev', ], 'debug' => [ - 'enabled ' => false, + 'enabled' => false, ], ]); diff --git a/src/Module/Velox/Internal/Config/Pipeline/TomlData.php b/src/Module/Velox/Internal/Config/Pipeline/TomlData.php index d0a68a0..8c85cea 100644 --- a/src/Module/Velox/Internal/Config/Pipeline/TomlData.php +++ b/src/Module/Velox/Internal/Config/Pipeline/TomlData.php @@ -4,6 +4,8 @@ namespace Internal\DLoad\Module\Velox\Internal\Config\Pipeline; +use Internal\Toml\Toml; + /** * Immutable TOML data container for pipeline processing. * @@ -19,7 +21,7 @@ final class TomlData /** * Creates a new immutable TOML data container. * - * @param array $data The configuration data array + * @param array $data The configuration data array */ public function __construct( private readonly array $data = [], @@ -36,23 +38,7 @@ public function __construct( */ public static function fromString(string $toml): self { - $instance = new self(); - $data = $instance->parseToml($toml); - return new self($data); - } - - /** - * Merges remote TOML configuration into local base configuration. - * - * @param string $localToml Base TOML configuration - * @param string $remoteToml Remote TOML configuration with plugins - * @return string Merged TOML configuration - */ - public static function mergeTomlStrings(string $localToml, string $remoteToml): string - { - $local = self::fromString($localToml); - $remote = self::fromString($remoteToml); - return $local->merge($remote)->toToml(); + return new self(Toml::parseToArray($toml)); } /** @@ -99,7 +85,7 @@ public function set(string $path, mixed $value): self */ public function toToml(): string { - return $this->arrayToToml($this->data); + return (string) Toml::encode($this->data); } /** @@ -115,314 +101,6 @@ public function getData(): array return $this->data; } - /** - * Simple TOML parser for basic configuration merging. - * - * @param string $toml TOML content - * @return array Parsed configuration - */ - private function parseToml(string $toml): array - { - $result = []; - $currentSection = null; // Track the current section context (e.g., "roadrunner" or "github.plugins") - $lines = \explode("\n", $toml); - - foreach ($lines as $line) { - $line = \trim($line); - - // Skip empty lines and comments (lines starting with #) - if ($line === '' || \str_starts_with($line, '#')) { - continue; - } - - // Parse section headers like [roadrunner] or [github.plugins.logger] - // These define the namespace for subsequent key-value pairs - if (\preg_match('/^\[([^\]]+)\]$/', $line, $matches)) { - $currentSection = $matches[1]; // Store the full section path - continue; - } - - // Parse key-value pairs in the format: key = value - // Handles both quoted and unquoted values - if (\preg_match('/^([^=]+)=(.+)$/', $line, $matches)) { - $key = \trim($matches[1]); - // Remove surrounding quotes and whitespace from values - $value = \trim($matches[2], ' "\''); - - if ($currentSection === null) { - // Top-level key-value pair (no section) - $result[$key] = $value; - } else { - // Nested key-value pair within a section - // Combine section path with key using dot notation - $this->setNestedValue($result, $currentSection . '.' . $key, $value); - } - } - } - - return $result; - } - - /** - * Converts array back to TOML format. - * - * @param array $data Configuration data - * @return string TOML content - */ - private function arrayToToml(array $data): string - { - $toml = ''; - $sections = []; // Collect associative arrays that will become TOML sections - - // First pass: output top-level scalar values and inline arrays - // This ensures proper TOML structure with values before sections - foreach ($data as $key => $value) { - if (!\is_array($value)) { - // Simple scalar value - output directly as key = "value" - $toml .= "{$key} = \"{$value}\"\n"; - } elseif ($this->isInlineArray($value)) { - // Sequential array - format as inline TOML array [item1, item2, ...] - $toml .= $this->formatKeyValue((string) $key, $value); - } else { - // Associative array - defer to sections for proper TOML structure - $sections[$key] = $value; - } - } - - // Add visual separator between top-level values and sections - // This improves readability of the generated TOML - if ($toml !== '' && !empty($sections)) { - $toml .= "\n"; - } - - // Apply custom ordering to sections for consistent output - // Prioritizes commonly used sections like 'roadrunner' first - $orderedSections = $this->orderSections($sections); - - // Second pass: output all sections (associative arrays) - // Each section becomes a [section.name] block in TOML - foreach ($orderedSections as $sectionKey => $sectionValue) { - $toml .= $this->sectionToToml($sectionKey, $sectionValue); - } - - // Clean up any trailing whitespace for cleaner output - return \rtrim($toml); - } - - /** - * Orders sections with priority: roadrunner first, then debug, logs, github, gitlab, etc. - * - * @param array $sections Sections to order - * @return array Ordered sections - */ - private function orderSections(array $sections): array - { - // Define priority order for commonly used configuration sections - // This ensures consistent output format with important sections first - $priority = ['roadrunner', 'debug', 'log', 'github', 'gitlab']; - $orderedSections = []; - $remainingSections = $sections; // Copy to track unprocessed sections - - // First pass: add priority sections in their defined order - // This maintains a predictable structure for configuration files - foreach ($priority as $sectionKey) { - if (isset($remainingSections[$sectionKey])) { - $orderedSections[$sectionKey] = $remainingSections[$sectionKey]; - unset($remainingSections[$sectionKey]); // Remove from remaining list - } - } - - // Second pass: append any remaining sections that weren't in priority list - // These will appear after priority sections in their original order - foreach ($remainingSections as $sectionKey => $sectionValue) { - $orderedSections[$sectionKey] = $sectionValue; - } - - return $orderedSections; - } - - /** - * Converts a section to TOML format. - * - * @param string $sectionName Section name - * @param array $data Section data - * @return string TOML section content - */ - private function sectionToToml(string $sectionName, array $data): string - { - $toml = ''; - - // Analyze section structure to determine rendering approach - // Check if this section contains nested associative arrays (subsections) - $hasSubsections = false; - foreach ($data as $value) { - if (\is_array($value) && !$this->isInlineArray($value)) { - $hasSubsections = true; - break; // Early exit once we find a subsection - } - } - - if (!$hasSubsections) { - // Simple flat section: only scalar values and inline arrays - // Format: [section_name] followed by key=value pairs - $toml .= "[{$sectionName}]\n"; - foreach ($data as $key => $value) { - $toml .= $this->formatKeyValue((string) $key, $value); - } - $toml .= "\n"; // Add blank line after section - } else { - // Complex section with mixed content: both simple values and nested sections - // Separate simple values from nested subsections for proper TOML structure - $simpleValues = []; // Scalar values and inline arrays - $subsections = []; // Associative arrays that become nested sections - - foreach ($data as $subKey => $subValue) { - if (\is_array($subValue) && !$this->isInlineArray($subValue)) { - // Associative array becomes a nested section - $subsections[$subKey] = $subValue; - } else { - // Scalar or inline array stays in this section - $simpleValues[$subKey] = $subValue; - } - } - - // Output the main section header only if there are simple values - // TOML requires section headers to have content, so we skip empty intermediate sections - if (!empty($simpleValues)) { - $toml .= "[{$sectionName}]\n"; - foreach ($simpleValues as $key => $value) { - $toml .= $this->formatKeyValue((string) $key, $value); - } - $toml .= "\n"; - } - - // Recursively render nested subsections with dotted notation - // e.g., [section.subsection] format - foreach ($subsections as $subKey => $subValue) { - $toml .= $this->renderNestedSection("{$sectionName}.{$subKey}", $subValue); - } - } - - return $toml; - } - - /** - * Renders a nested section recursively. - * - * @param string $sectionPath Full section path (e.g., "github.plugins.logger") - * @param array $data Section data - * @return string TOML section content - */ - private function renderNestedSection(string $sectionPath, array $data): string - { - $toml = ''; - - // Recursively separate content into simple values and nested subsections - // This maintains proper TOML hierarchy for deeply nested configurations - $simpleValues = []; // Scalar values and inline arrays for this section - $subsections = []; // Nested associative arrays for deeper sections - - foreach ($data as $key => $value) { - if (\is_array($value) && !$this->isInlineArray($value)) { - // Nested associative array - becomes a deeper subsection - $subsections[$key] = $value; - } else { - // Scalar value or inline array - stays at current nesting level - $simpleValues[$key] = $value; - } - } - - // Render section header and content based on what we found - // Rules: - // 1. If we have simple values, create the section header and add them - // 2. If we have no subsections but the section exists, create empty section - // 3. If we only have subsections and no simple values, skip this level's header - if (!empty($simpleValues) || empty($subsections)) { - $toml .= "[{$sectionPath}]\n"; - // Output all simple key-value pairs for this section level - foreach ($simpleValues as $key => $value) { - $toml .= $this->formatKeyValue((string) $key, $value); - } - $toml .= "\n"; // Blank line after section content - } - - // Recursively render all nested subsections with extended path - // Each subsection gets a dotted path like 'parent.child.grandchild' - foreach ($subsections as $key => $value) { - $toml .= $this->renderNestedSection("{$sectionPath}.{$key}", $value); - } - - return $toml; - } - - /** - * Formats a key-value pair for TOML output. - * - * @param string $key The key - * @param mixed $value The value - * @return string Formatted TOML key-value pair - */ - private function formatKeyValue(string $key, mixed $value): string - { - if (\is_array($value)) { - // Array values become inline TOML arrays: key = ["item1", "item2"] - // Delegate to specialized array formatting method - return "{$key} = " . $this->formatArrayValue($value) . "\n"; - } - - // Scalar values become quoted strings: key = "value" - // All values are quoted for consistency and safety - return "{$key} = \"{$value}\"\n"; - } - - /** - * Formats an array value for TOML output. - * - * @param array $array The array to format - * @return string Formatted TOML array - */ - private function formatArrayValue(array $array): string - { - $items = []; - - // Convert each array element to a TOML-compatible string representation - foreach ($array as $item) { - if (\is_array($item)) { - // Nested arrays aren't natively supported in TOML inline arrays - // Serialize to JSON string as a workaround for complex data structures - $items[] = '"' . \json_encode($item) . '"'; - } else { - // Simple scalar values are converted to strings and quoted - // This ensures proper TOML syntax for all data types - $items[] = '"' . (string) $item . '"'; - } - } - - // Join all items with commas and wrap in square brackets - // Result: ["item1", "item2", "item3"] - return '[' . \implode(', ', $items) . ']'; - } - - /** - * Determines if an array should be rendered as an inline array rather than a section. - * - * @param array $array The array to check - * @return bool True if it should be an inline array - */ - private function isInlineArray(array $array): bool - { - // Empty arrays are treated as sections, not inline arrays - // This prevents creating empty inline arrays and ensures proper TOML structure - if (empty($array)) { - return false; - } - - // Check if array has sequential numeric keys starting from 0 - // Only truly sequential arrays (0, 1, 2, ...) become inline TOML arrays - // Associative arrays with string keys become TOML sections instead - return \array_keys($array) === \range(0, \count($array) - 1); - } - /** * Performs a deep merge of two arrays, recursively merging nested structures. * diff --git a/tests/Unit/Module/Velox/Internal/Config/Pipeline/TomlDataTest.php b/tests/Unit/Module/Velox/Internal/Config/Pipeline/TomlDataTest.php index c73a176..aa94681 100644 --- a/tests/Unit/Module/Velox/Internal/Config/Pipeline/TomlDataTest.php +++ b/tests/Unit/Module/Velox/Internal/Config/Pipeline/TomlDataTest.php @@ -12,31 +12,6 @@ #[CoversClass(TomlData::class)] final class TomlDataTest extends TestCase { - public static function provideNestedSectionData(): \Generator - { - yield 'simple nested section' => [ - "[github.plugins.logger]\ntype = \"logger\"", - ['github' => ['plugins' => ['logger' => ['type' => 'logger']]]], - ]; - - yield 'multiple nested sections' => [ - "[github.plugins.logger]\ntype = \"logger\"\n\n[github.plugins.cache]\ntype = \"cache\"", - [ - 'github' => [ - 'plugins' => [ - 'logger' => ['type' => 'logger'], - 'cache' => ['type' => 'cache'], - ], - ], - ], - ]; - - yield 'deeply nested section' => [ - "[a.b.c.d]\nvalue = \"deep\"", - ['a' => ['b' => ['c' => ['d' => ['value' => 'deep']]]]], - ]; - } - public static function provideSetPathData(): \Generator { yield 'simple key' => [ @@ -76,18 +51,16 @@ public static function provideQuotedValues(): \Generator ['key' => 'value with spaces'], ]; - yield 'no quotes' => [ - 'key = simple_value', - ['key' => 'simple_value'], - ]; - yield 'mixed quotes in section' => [ - "[section]\ndouble = \"quoted\"\nsingle = 'quoted'\nbare = unquoted", + << [ 'double' => 'quoted', 'single' => 'quoted', - 'bare' => 'unquoted', ], ], ]; @@ -130,41 +103,6 @@ public function testFromStringCreatesInstanceFromTomlString(): void self::assertSame($expectedData, $tomlData->getData()); } - public function testFromStringHandlesEmptyString(): void - { - // Act - $tomlData = TomlData::fromString(''); - - // Assert - self::assertSame([], $tomlData->getData()); - } - - public function testFromStringHandlesCommentsAndEmptyLines(): void - { - // Arrange - $toml = "# This is a comment\n\nkey = \"value\"\n# Another comment\n\n[section]\n# Comment in section\nnested = \"data\""; - $expectedData = [ - 'key' => 'value', - 'section' => ['nested' => 'data'], - ]; - - // Act - $tomlData = TomlData::fromString($toml); - - // Assert - self::assertSame($expectedData, $tomlData->getData()); - } - - #[DataProvider('provideNestedSectionData')] - public function testFromStringHandlesNestedSections(string $toml, array $expectedData): void - { - // Act - $tomlData = TomlData::fromString($toml); - - // Assert - self::assertSame($expectedData, $tomlData->getData()); - } - public function testMergeCreatesNewInstanceWithMergedData(): void { // Arrange @@ -263,12 +201,13 @@ public function testToTomlConvertsDataToTomlString(): void ]; $tomlData = new TomlData($data); $expectedToml = <<toToml(); @@ -310,11 +249,11 @@ public function testToTomlHandlesMixedSectionTypes(): void ]; $tomlData = new TomlData($data); $expectedToml = <<getData(), $roundTripData->getData()); } - public function testToTomlHandlesEmptyNestedSections(): void - { - // Arrange - $data = [ - 'section' => [ - 'empty_subsection' => [], - 'populated_subsection' => ['key' => 'value'], - ], - ]; - $tomlData = new TomlData($data); - $expectedToml = <<toToml(); - - // Assert - self::assertSame($expectedToml, $result); - } - public function testParseTomlWithComplexNestedStructure(): void { // Arrange @@ -624,140 +513,4 @@ public function testParseTomlWithComplexNestedStructure(): void // Assert self::assertSame($expectedData, $tomlData->getData()); } - - public function testToTomlOrdersSectionsWithRoadrunnerFirst(): void - { - // Arrange - sections in different order - $data = [ - 'github' => ['plugins' => ['logger' => 'enabled']], - 'log' => ['level' => 'debug'], - 'roadrunner' => ['ref' => 'v2025.1.1'], - 'debug' => ['enabled' => 'true'], - 'other' => ['key' => 'value'], - ]; - $tomlData = new TomlData($data); - - // Act - $result = $tomlData->toToml(); - - // Assert - roadrunner should be first, then debug, log, github, then others - $expectedToml = << ['ref' => 'v2025.1.1'], - ]; - $tomlData = new TomlData($data); - - // Act - $result = $tomlData->toToml(); - - // Assert - "v" prefix should be preserved - $expectedToml = << ['ref' => ''], - ]; - $tomlData = new TomlData($data); - - // Act - $result = $tomlData->toToml(); - - // Assert - empty ref should remain empty - $expectedToml = << ['ref' => 123], - ]; - $tomlData = new TomlData($data); - - // Act - $result = $tomlData->toToml(); - - // Assert - non-string ref should remain unchanged - $expectedToml = << ['key' => 'value'], - 'gitlab' => ['url' => 'gitlab.com'], - 'github' => ['token' => 'secret'], - 'log' => ['level' => 'info'], - 'debug' => ['enabled' => 'false'], - 'roadrunner' => ['ref' => 'v2025.1.1'], - ]; - $tomlData = new TomlData($data); - - // Act - $result = $tomlData->toToml(); - - // Assert - proper ordering and normalization - $expectedToml = <<