From 845cdd56ac50131c318ca39e24b7bf1af1b4c69a Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Thu, 26 Oct 2023 20:09:28 +0200 Subject: [PATCH 01/19] remove public services (only alias) --- src/Resources/config/services.yaml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index f1efa49..5d4df3f 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -7,19 +7,16 @@ services: - "%pentatrion_vite.default_build%" - "%pentatrion_vite.builds%" - "%pentatrion_vite.throw_on_missing_entry%" - public: true vite.tag_renderer: class: Pentatrion\ViteBundle\Asset\TagRenderer arguments: - - default - - [] + - default # Default default_build + - [] # Default builds - "@?event_dispatcher" - public: true Pentatrion\ViteBundle\Asset\EntrypointsLookup: alias: "vite.entrypoints_lookup" - public: true vite.entrypoint_renderer: @@ -29,11 +26,9 @@ services: - "@vite.tag_renderer" - "%pentatrion_vite.absolute_url%" - "@?router" - public: true Pentatrion\ViteBundle\Asset\EntrypointRenderer: alias: "vite.entrypoint_renderer" - public: true vite.twig_entry_files_extension: @@ -50,7 +45,6 @@ services: - "@http_client" - "@vite.entrypoints_lookup" - "%pentatrion_vite.proxy_origin%" - public: true Pentatrion\ViteBundle\Asset\ViteAssetVersionStrategy: arguments: From db46092ac5b49e1d63673f5fac1387aa0e355a5e Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 27 Oct 2023 10:28:53 +0200 Subject: [PATCH 02/19] add phpunit package --- .phpunit.result.cache | 1 + CHANGELOG.md | 4 + bin/phpunit | 19 + composer.json | 23 +- composer.lock | 2934 +++++++++++++---- phpunit.xml.dist | 34 + .../PentatrionViteExtension.php | 2 +- src/Resources/config/services.yaml | 16 +- tests/Asset/TagRendererTest.php | 13 + 9 files changed, 2387 insertions(+), 659 deletions(-) create mode 100644 .phpunit.result.cache create mode 100755 bin/phpunit create mode 100644 phpunit.xml.dist create mode 100644 tests/Asset/TagRendererTest.php diff --git a/.phpunit.result.cache b/.phpunit.result.cache new file mode 100644 index 0000000..8c20c2c --- /dev/null +++ b/.phpunit.result.cache @@ -0,0 +1 @@ +{"version":1,"defects":[],"times":{"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTagBasic":1.815}} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9279a88..fc337e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## Next + +- make services privates. + ## v5.0.1 - remove deprecated options diff --git a/bin/phpunit b/bin/phpunit new file mode 100755 index 0000000..f26f2c7 --- /dev/null +++ b/bin/phpunit @@ -0,0 +1,19 @@ +#!/usr/bin/env php +=8.1", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^1.1.7|^2|^3", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/cache-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.3.6" }, "conflict": { "doctrine/dbal": "<2.13.1", @@ -315,8 +312,8 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/dbal": "^2.13.1|^3.0", - "predis/predis": "^1.1", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", "symfony/config": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", @@ -351,14 +348,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides an extended PSR-6, PSR-16 (and tags) implementation", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", "homepage": "https://symfony.com", "keywords": [ "caching", "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.1.3" + "source": "https://github.com/symfony/cache/tree/v6.3.6" }, "funding": [ { @@ -374,33 +371,30 @@ "type": "tidelift" } ], - "time": "2022-07-29T07:42:06+00:00" + "time": "2023-10-17T14:44:58+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.1.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "2eab7fa459af6d75c6463e63e633b667a9b761d3" + "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/2eab7fa459af6d75c6463e63e633b667a9b761d3", - "reference": "2eab7fa459af6d75c6463e63e633b667a9b761d3", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/ad945640ccc0ae6e208bcea7d7de4b39b569896b", + "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b", "shasum": "" }, "require": { "php": ">=8.1", "psr/cache": "^3.0" }, - "suggest": { - "symfony/cache-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -437,7 +431,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/cache-contracts/tree/v3.3.0" }, "funding": [ { @@ -453,41 +447,39 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/config", - "version": "v6.1.3", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "a0645dc585d378b73c01115dd7ab9348f7d40c85" + "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/a0645dc585d378b73c01115dd7ab9348f7d40c85", - "reference": "a0645dc585d378b73c01115dd7ab9348f7d40c85", + "url": "https://api.github.com/repos/symfony/config/zipball/b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", + "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/filesystem": "^5.4|^6.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<5.4" + "symfony/finder": "<5.4", + "symfony/service-contracts": "<2.5" }, "require-dev": { "symfony/event-dispatcher": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "symfony/messenger": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^5.4|^6.0" }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, "type": "library", "autoload": { "psr-4": { @@ -514,7 +506,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.1.3" + "source": "https://github.com/symfony/config/tree/v6.3.2" }, "funding": [ { @@ -530,33 +522,34 @@ "type": "tidelift" } ], - "time": "2022-07-20T15:00:40+00:00" + "time": "2023-07-19T20:22:16+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.1.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "079e336a1880f457b219aecc3d41bef2f1093b0b" + "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/079e336a1880f457b219aecc3d41bef2f1093b0b", - "reference": "079e336a1880f457b219aecc3d41bef2f1093b0b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2ed62b3bf98346e1f45529a7b6be2196739bb993", + "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993", "shasum": "" }, "require": { "php": ">=8.1", "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/service-contracts": "^1.1.6|^2.0|^3.0" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.2.10" }, "conflict": { "ext-psr": "<1.1|>=2", "symfony/config": "<6.1", "symfony/finder": "<5.4", - "symfony/proxy-manager-bridge": "<5.4", + "symfony/proxy-manager-bridge": "<6.3", "symfony/yaml": "<5.4" }, "provide": { @@ -568,13 +561,6 @@ "symfony/expression-language": "^5.4|^6.0", "symfony/yaml": "^5.4|^6.0" }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, "type": "library", "autoload": { "psr-4": { @@ -601,7 +587,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.1.3" + "source": "https://github.com/symfony/dependency-injection/tree/v6.3.5" }, "funding": [ { @@ -617,20 +603,20 @@ "type": "tidelift" } ], - "time": "2022-07-20T13:46:29+00:00" + "time": "2023-09-25T16:46:40+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.1.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", - "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { @@ -639,7 +625,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -668,7 +654,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.1.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" }, "funding": [ { @@ -684,20 +670,20 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/error-handler", - "version": "v6.1.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "736e42db3fd586d91820355988698e434e1d8419" + "reference": "1f69476b64fb47105c06beef757766c376b548c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/736e42db3fd586d91820355988698e434e1d8419", - "reference": "736e42db3fd586d91820355988698e434e1d8419", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/1f69476b64fb47105c06beef757766c376b548c4", + "reference": "1f69476b64fb47105c06beef757766c376b548c4", "shasum": "" }, "require": { @@ -705,8 +691,11 @@ "psr/log": "^1|^2|^3", "symfony/var-dumper": "^5.4|^6.0" }, + "conflict": { + "symfony/deprecation-contracts": "<2.5" + }, "require-dev": { - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-kernel": "^5.4|^6.0", "symfony/serializer": "^5.4|^6.0" }, @@ -739,7 +728,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.1.3" + "source": "https://github.com/symfony/error-handler/tree/v6.3.5" }, "funding": [ { @@ -755,28 +744,29 @@ "type": "tidelift" } ], - "time": "2022-07-29T07:42:06+00:00" + "time": "2023-09-12T06:57:20+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.1.0", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347" + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a0449a7ad7daa0f7c0acd508259f80544ab5a347", - "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e", + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/event-dispatcher-contracts": "^2|^3" + "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<5.4" + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" }, "provide": { "psr/event-dispatcher-implementation": "1.0", @@ -789,13 +779,9 @@ "symfony/error-handler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/http-foundation": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/stopwatch": "^5.4|^6.0" }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, "type": "library", "autoload": { "psr-4": { @@ -822,7 +808,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.1.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2" }, "funding": [ { @@ -838,33 +824,30 @@ "type": "tidelift" } ], - "time": "2022-05-05T16:51:07+00:00" + "time": "2023-07-06T06:56:43+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.1.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "02ff5eea2f453731cfbc6bc215e456b781480448" + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/02ff5eea2f453731cfbc6bc215e456b781480448", - "reference": "02ff5eea2f453731cfbc6bc215e456b781480448", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", "shasum": "" }, "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -901,7 +884,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0" }, "funding": [ { @@ -917,20 +900,20 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/filesystem", - "version": "v6.1.3", + "version": "v6.3.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "c780e677cddda78417fa5187a7c6cd2f21110db9" + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/c780e677cddda78417fa5187a7c6cd2f21110db9", - "reference": "c780e677cddda78417fa5187a7c6cd2f21110db9", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", "shasum": "" }, "require": { @@ -964,7 +947,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.1.3" + "source": "https://github.com/symfony/filesystem/tree/v6.3.1" }, "funding": [ { @@ -980,20 +963,20 @@ "type": "tidelift" } ], - "time": "2022-07-20T14:45:06+00:00" + "time": "2023-06-01T08:30:39+00:00" }, { "name": "symfony/finder", - "version": "v6.1.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709" + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/39696bff2c2970b3779a5cac7bf9f0b88fc2b709", - "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709", + "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4", + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4", "shasum": "" }, "require": { @@ -1028,7 +1011,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.1.3" + "source": "https://github.com/symfony/finder/tree/v6.3.5" }, "funding": [ { @@ -1044,20 +1027,20 @@ "type": "tidelift" } ], - "time": "2022-07-29T07:42:06+00:00" + "time": "2023-09-26T12:56:25+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.1.3", + "version": "v6.3.6", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "7973a1c66b8b58613d1bf3ed0a0a671d58d0991f" + "reference": "5b5dca452a70d06d0463d3aeae640b2d034ef485" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/7973a1c66b8b58613d1bf3ed0a0a671d58d0991f", - "reference": "7973a1c66b8b58613d1bf3ed0a0a671d58d0991f", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/5b5dca452a70d06d0463d3aeae640b2d034ef485", + "reference": "5b5dca452a70d06d0463d3aeae640b2d034ef485", "shasum": "" }, "require": { @@ -1066,14 +1049,14 @@ "php": ">=8.1", "symfony/cache": "^5.4|^6.0", "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/dependency-injection": "^6.3.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.1", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/filesystem": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^6.1", + "symfony/http-foundation": "^6.3", + "symfony/http-kernel": "^6.3", "symfony/polyfill-mbstring": "~1.0", "symfony/routing": "^5.4|^6.0" }, @@ -1082,77 +1065,70 @@ "doctrine/persistence": "<1.3", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "phpunit/phpunit": "<5.4.3", "symfony/asset": "<5.4", + "symfony/clock": "<6.3", "symfony/console": "<5.4", - "symfony/dom-crawler": "<5.4", + "symfony/dom-crawler": "<6.3", "symfony/dotenv": "<5.4", "symfony/form": "<5.4", - "symfony/http-client": "<5.4", + "symfony/http-client": "<6.3", "symfony/lock": "<5.4", "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4", - "symfony/mime": "<5.4", + "symfony/messenger": "<6.3", + "symfony/mime": "<6.2", "symfony/property-access": "<5.4", "symfony/property-info": "<5.4", "symfony/security-core": "<5.4", "symfony/security-csrf": "<5.4", - "symfony/serializer": "<6.1", + "symfony/serializer": "<6.3", "symfony/stopwatch": "<5.4", - "symfony/translation": "<5.4", + "symfony/translation": "<6.2.8", "symfony/twig-bridge": "<5.4", "symfony/twig-bundle": "<5.4", - "symfony/validator": "<5.4", + "symfony/validator": "<6.3", "symfony/web-profiler-bundle": "<5.4", "symfony/workflow": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.13.1", + "doctrine/annotations": "^1.13.1|^2", "doctrine/persistence": "^1.3|^2|^3", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/asset": "^5.4|^6.0", + "symfony/asset-mapper": "^6.3", "symfony/browser-kit": "^5.4|^6.0", + "symfony/clock": "^6.2", "symfony/console": "^5.4.9|^6.0.9", "symfony/css-selector": "^5.4|^6.0", - "symfony/dom-crawler": "^5.4|^6.0", + "symfony/dom-crawler": "^6.3", "symfony/dotenv": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/form": "^5.4|^6.0", "symfony/html-sanitizer": "^6.1", - "symfony/http-client": "^5.4|^6.0", + "symfony/http-client": "^6.3", "symfony/lock": "^5.4|^6.0", "symfony/mailer": "^5.4|^6.0", - "symfony/messenger": "^6.1", - "symfony/mime": "^5.4|^6.0", + "symfony/messenger": "^6.3", + "symfony/mime": "^6.2", "symfony/notifier": "^5.4|^6.0", "symfony/polyfill-intl-icu": "~1.0", "symfony/process": "^5.4|^6.0", "symfony/property-info": "^5.4|^6.0", "symfony/rate-limiter": "^5.4|^6.0", + "symfony/scheduler": "^6.3", "symfony/security-bundle": "^5.4|^6.0", "symfony/semaphore": "^5.4|^6.0", - "symfony/serializer": "^6.1", + "symfony/serializer": "^6.3", "symfony/stopwatch": "^5.4|^6.0", "symfony/string": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", + "symfony/translation": "^6.2.8", "symfony/twig-bundle": "^5.4|^6.0", "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0", + "symfony/validator": "^6.3", "symfony/web-link": "^5.4|^6.0", "symfony/workflow": "^5.4|^6.0", "symfony/yaml": "^5.4|^6.0", "twig/twig": "^2.10|^3.0" }, - "suggest": { - "ext-apcu": "For best performance of the system caches", - "symfony/console": "For using the console commands", - "symfony/form": "For using forms", - "symfony/property-info": "For using the property_info service", - "symfony/serializer": "For using the serializer service", - "symfony/validator": "For using validation", - "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", - "symfony/yaml": "For using the debug:config and lint:yaml commands" - }, "type": "symfony-bundle", "autoload": { "psr-4": { @@ -1179,7 +1155,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.1.3" + "source": "https://github.com/symfony/framework-bundle/tree/v6.3.6" }, "funding": [ { @@ -1195,27 +1171,32 @@ "type": "tidelift" } ], - "time": "2022-07-29T06:42:38+00:00" + "time": "2023-10-12T17:41:20+00:00" }, { "name": "symfony/http-client", - "version": "v6.1.3", + "version": "v6.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "1ef59920a9cedf223e8564ae8ad7608cbe799b4d" + "reference": "ab8446f997efb9913627e9da10fa784d2182fe92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/1ef59920a9cedf223e8564ae8ad7608cbe799b4d", - "reference": "1ef59920a9cedf223e8564ae8ad7608cbe799b4d", + "url": "https://api.github.com/repos/symfony/http-client/zipball/ab8446f997efb9913627e9da10fa784d2182fe92", + "reference": "ab8446f997efb9913627e9da10fa784d2182fe92", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "^3", - "symfony/service-contracts": "^1.0|^2|^3" + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.3" }, "provide": { "php-http/async-client-implementation": "*", @@ -1262,8 +1243,11 @@ ], "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", "homepage": "https://symfony.com", + "keywords": [ + "http" + ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.1.3" + "source": "https://github.com/symfony/http-client/tree/v6.3.6" }, "funding": [ { @@ -1279,32 +1263,29 @@ "type": "tidelift" } ], - "time": "2022-07-28T13:40:41+00:00" + "time": "2023-10-06T10:08:56+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.1.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800" + "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/fd038f08c623ab5d22b26e9ba35afe8c79071800", - "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/3b66325d0176b4ec826bffab57c9037d759c31fb", + "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb", "shasum": "" }, "require": { "php": ">=8.1" }, - "suggest": { - "symfony/http-client-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -1344,7 +1325,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.3.0" }, "funding": [ { @@ -1360,35 +1341,40 @@ "type": "tidelift" } ], - "time": "2022-04-22T07:30:54+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.1.3", + "version": "v6.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "b03712c93759a81fc243ecc18ec4637958afebdb" + "reference": "c186627f52febe09c6d5270b04f8462687a250a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b03712c93759a81fc243ecc18ec4637958afebdb", - "reference": "b03712c93759a81fc243ecc18ec4637958afebdb", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c186627f52febe09c6d5270b04f8462687a250a6", + "reference": "c186627f52febe09c6d5270b04f8462687a250a6", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-mbstring": "~1.1" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "symfony/cache": "<6.3" }, "require-dev": { - "predis/predis": "~1.0", - "symfony/cache": "^5.4|^6.0", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.3", + "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0" - }, - "suggest": { - "symfony/mime": "To use the file extension guesser" + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^5.4|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" }, "type": "library", "autoload": { @@ -1416,7 +1402,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.1.3" + "source": "https://github.com/symfony/http-foundation/tree/v6.3.6" }, "funding": [ { @@ -1432,28 +1418,29 @@ "type": "tidelift" } ], - "time": "2022-07-27T15:50:51+00:00" + "time": "2023-10-17T11:32:53+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.1.3", + "version": "v6.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "0692bc185a1dbb54864686a1fc6785667279da70" + "reference": "4945f5001b06ff9080cd3d8f1f9f069094c0d156" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/0692bc185a1dbb54864686a1fc6785667279da70", - "reference": "0692bc185a1dbb54864686a1fc6785667279da70", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4945f5001b06ff9080cd3d8f1f9f069094c0d156", + "reference": "4945f5001b06ff9080cd3d8f1f9f069094c0d156", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", - "symfony/error-handler": "^6.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.3", "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-foundation": "^6.3.4", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -1461,15 +1448,18 @@ "symfony/cache": "<5.4", "symfony/config": "<6.1", "symfony/console": "<5.4", - "symfony/dependency-injection": "<6.1", + "symfony/dependency-injection": "<6.3.4", "symfony/doctrine-bridge": "<5.4", "symfony/form": "<5.4", "symfony/http-client": "<5.4", + "symfony/http-client-contracts": "<2.5", "symfony/mailer": "<5.4", "symfony/messenger": "<5.4", "symfony/translation": "<5.4", + "symfony/translation-contracts": "<2.5", "symfony/twig-bridge": "<5.4", "symfony/validator": "<5.4", + "symfony/var-dumper": "<6.3", "twig/twig": "<2.13" }, "provide": { @@ -1478,28 +1468,27 @@ "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "symfony/browser-kit": "^5.4|^6.0", + "symfony/clock": "^6.2", "symfony/config": "^6.1", "symfony/console": "^5.4|^6.0", "symfony/css-selector": "^5.4|^6.0", - "symfony/dependency-injection": "^6.1", + "symfony/dependency-injection": "^6.3.4", "symfony/dom-crawler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symfony/http-client-contracts": "^1.1|^2|^3", + "symfony/http-client-contracts": "^2.5|^3", "symfony/process": "^5.4|^6.0", + "symfony/property-access": "^5.4.5|^6.0.5", "symfony/routing": "^5.4|^6.0", + "symfony/serializer": "^6.3", "symfony/stopwatch": "^5.4|^6.0", "symfony/translation": "^5.4|^6.0", - "symfony/translation-contracts": "^1.1|^2|^3", + "symfony/translation-contracts": "^2.5|^3", "symfony/uid": "^5.4|^6.0", + "symfony/validator": "^6.3", + "symfony/var-exporter": "^6.2", "twig/twig": "^2.13|^3.0.4" }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "" - }, "type": "library", "autoload": { "psr-4": { @@ -1526,7 +1515,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.1.3" + "source": "https://github.com/symfony/http-kernel/tree/v6.3.6" }, "funding": [ { @@ -1542,20 +1531,20 @@ "type": "tidelift" } ], - "time": "2022-07-29T12:59:10+00:00" + "time": "2023-10-21T13:12:51+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.26.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -1570,7 +1559,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1608,7 +1597,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -1624,20 +1613,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.26.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -1652,7 +1641,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1691,7 +1680,170 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-28T09:04:16+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", + "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-php80": "^1.14" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.28.0" }, "funding": [ { @@ -1707,46 +1859,41 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-08-16T06:22:46+00:00" }, { "name": "symfony/routing", - "version": "v6.1.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "ef9108b3a88045b7546e808fb404ddb073dd35ea" + "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/ef9108b3a88045b7546e808fb404ddb073dd35ea", - "reference": "ef9108b3a88045b7546e808fb404ddb073dd35ea", + "url": "https://api.github.com/repos/symfony/routing/zipball/82616e59acd3e3d9c916bba798326cb7796d7d31", + "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "doctrine/annotations": "<1.12", - "symfony/config": "<5.4", + "symfony/config": "<6.2", "symfony/dependency-injection": "<5.4", "symfony/yaml": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.12", + "doctrine/annotations": "^1.12|^2", "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", + "symfony/config": "^6.2", "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/http-foundation": "^5.4|^6.0", "symfony/yaml": "^5.4|^6.0" }, - "suggest": { - "symfony/config": "For using the all-in-one router or any loader", - "symfony/expression-language": "For using expression matching", - "symfony/http-foundation": "For using a Symfony Request object", - "symfony/yaml": "For using the YAML loader" - }, "type": "library", "autoload": { "psr-4": { @@ -1779,7 +1926,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.1.3" + "source": "https://github.com/symfony/routing/tree/v6.3.5" }, "funding": [ { @@ -1795,20 +1942,20 @@ "type": "tidelift" } ], - "time": "2022-07-20T15:00:40+00:00" + "time": "2023-09-20T16:05:51+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.1.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", - "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", "shasum": "" }, "require": { @@ -1818,13 +1965,10 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -1864,7 +2008,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" }, "funding": [ { @@ -1880,32 +2024,29 @@ "type": "tidelift" } ], - "time": "2022-05-30T19:18:58+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.1.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "606be0f48e05116baef052f7f3abdb345c8e02cc" + "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/606be0f48e05116baef052f7f3abdb345c8e02cc", - "reference": "606be0f48e05116baef052f7f3abdb345c8e02cc", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/02c24deb352fb0d79db5486c0c79905a85e37e86", + "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86", "shasum": "" }, "require": { "php": ">=8.1" }, - "suggest": { - "symfony/translation-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -1945,7 +2086,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.3.0" }, "funding": [ { @@ -1961,52 +2102,55 @@ "type": "tidelift" } ], - "time": "2022-06-27T17:24:16+00:00" + "time": "2023-05-30T17:17:10+00:00" }, { "name": "symfony/twig-bridge", - "version": "v6.1.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "e16ffa5cf4de7b4fe753e5f2cd8b62067819a342" + "reference": "18f2cbe1d46ad43c4d3bd45e5e6279172068e064" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e16ffa5cf4de7b4fe753e5f2cd8b62067819a342", - "reference": "e16ffa5cf4de7b4fe753e5f2cd8b62067819a342", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/18f2cbe1d46ad43c4d3bd45e5e6279172068e064", + "reference": "18f2cbe1d46ad43c4d3bd45e5e6279172068e064", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/translation-contracts": "^1.1|^2|^3", + "symfony/translation-contracts": "^2.5|^3", "twig/twig": "^2.13|^3.0.4" }, "conflict": { "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.4", - "symfony/form": "<6.1", + "symfony/form": "<6.3", "symfony/http-foundation": "<5.4", - "symfony/http-kernel": "<5.4", + "symfony/http-kernel": "<6.2", + "symfony/mime": "<6.2", "symfony/translation": "<5.4", "symfony/workflow": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.12", - "egulias/email-validator": "^2.1.10|^3", + "doctrine/annotations": "^1.12|^2", + "egulias/email-validator": "^2.1.10|^3|^4", + "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/asset": "^5.4|^6.0", + "symfony/asset-mapper": "^6.3", "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symfony/form": "^6.1", + "symfony/form": "^6.3", "symfony/html-sanitizer": "^6.1", "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", "symfony/intl": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", + "symfony/mime": "^6.2", "symfony/polyfill-intl-icu": "~1.0", "symfony/property-info": "^5.4|^6.0", "symfony/routing": "^5.4|^6.0", @@ -2014,9 +2158,9 @@ "symfony/security-core": "^5.4|^6.0", "symfony/security-csrf": "^5.4|^6.0", "symfony/security-http": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", + "symfony/serializer": "^6.2", "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", + "symfony/translation": "^6.1", "symfony/web-link": "^5.4|^6.0", "symfony/workflow": "^5.4|^6.0", "symfony/yaml": "^5.4|^6.0", @@ -2024,23 +2168,6 @@ "twig/inky-extra": "^2.12|^3", "twig/markdown-extra": "^2.12|^3" }, - "suggest": { - "symfony/asset": "For using the AssetExtension", - "symfony/expression-language": "For using the ExpressionExtension", - "symfony/finder": "", - "symfony/form": "For using the FormExtension", - "symfony/html-sanitizer": "For using the HtmlSanitizerExtension", - "symfony/http-kernel": "For using the HttpKernelExtension", - "symfony/routing": "For using the RoutingExtension", - "symfony/security-core": "For using the SecurityExtension", - "symfony/security-csrf": "For using the CsrfExtension", - "symfony/security-http": "For using the LogoutUrlExtension", - "symfony/stopwatch": "For using the StopwatchExtension", - "symfony/translation": "For using the TranslationExtension", - "symfony/var-dumper": "For using the DumpExtension", - "symfony/web-link": "For using the WebLinkExtension", - "symfony/yaml": "For using the YamlExtension" - }, "type": "symfony-bridge", "autoload": { "psr-4": { @@ -2067,7 +2194,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.1.3" + "source": "https://github.com/symfony/twig-bridge/tree/v6.3.5" }, "funding": [ { @@ -2083,31 +2210,30 @@ "type": "tidelift" } ], - "time": "2022-07-20T13:46:29+00:00" + "time": "2023-09-12T06:57:20+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.1.1", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "a2abab10068525a7f5a879e40e411d369d688545" + "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/a2abab10068525a7f5a879e40e411d369d688545", - "reference": "a2abab10068525a7f5a879e40e411d369d688545", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", + "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "php": ">=8.1", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", + "symfony/config": "^6.1", + "symfony/dependency-injection": "^6.1", "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/twig-bridge": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", + "symfony/twig-bridge": "^6.3", "twig/twig": "^2.13|^3.0.4" }, "conflict": { @@ -2115,7 +2241,7 @@ "symfony/translation": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4", + "doctrine/annotations": "^1.10.4|^2", "symfony/asset": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", @@ -2153,7 +2279,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.1.1" + "source": "https://github.com/symfony/twig-bundle/tree/v6.3.0" }, "funding": [ { @@ -2169,42 +2295,38 @@ "type": "tidelift" } ], - "time": "2022-05-27T16:55:36+00:00" + "time": "2023-05-06T09:53:41+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.1.3", + "version": "v6.3.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427" + "reference": "999ede244507c32b8e43aebaa10e9fce20de7c97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427", - "reference": "d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/999ede244507c32b8e43aebaa10e9fce20de7c97", + "reference": "999ede244507c32b8e43aebaa10e9fce20de7c97", "shasum": "" }, "require": { "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "phpunit/phpunit": "<5.4.3", "symfony/console": "<5.4" }, "require-dev": { "ext-iconv": "*", "symfony/console": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", "symfony/process": "^5.4|^6.0", "symfony/uid": "^5.4|^6.0", "twig/twig": "^2.13|^3.0.4" }, - "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-intl": "To show region name in time zone dump", - "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" - }, "bin": [ "Resources/bin/var-dump-server" ], @@ -2241,7 +2363,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.1.3" + "source": "https://github.com/symfony/var-dumper/tree/v6.3.6" }, "funding": [ { @@ -2257,20 +2379,20 @@ "type": "tidelift" } ], - "time": "2022-07-20T13:46:29+00:00" + "time": "2023-10-12T18:45:56+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.1.3", + "version": "v6.3.6", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "b49350f45cebbba6e5286485264b912f2bcfc9ef" + "reference": "374d289c13cb989027274c86206ddc63b16a2441" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b49350f45cebbba6e5286485264b912f2bcfc9ef", - "reference": "b49350f45cebbba6e5286485264b912f2bcfc9ef", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/374d289c13cb989027274c86206ddc63b16a2441", + "reference": "374d289c13cb989027274c86206ddc63b16a2441", "shasum": "" }, "require": { @@ -2310,10 +2432,12 @@ "export", "hydrate", "instantiate", + "lazy-loading", + "proxy", "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.1.3" + "source": "https://github.com/symfony/var-exporter/tree/v6.3.6" }, "funding": [ { @@ -2329,20 +2453,20 @@ "type": "tidelift" } ], - "time": "2022-07-04T16:01:56+00:00" + "time": "2023-10-13T09:16:49+00:00" }, { "name": "twig/twig", - "version": "v3.4.2", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077" + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", - "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", "shasum": "" }, "require": { @@ -2351,15 +2475,10 @@ "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { - "psr/container": "^1.0", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, "autoload": { "psr-4": { "Twig\\": "src/" @@ -2393,7 +2512,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.4.2" + "source": "https://github.com/twigphp/Twig/tree/v3.7.1" }, "funding": [ { @@ -2405,22 +2524,22 @@ "type": "tidelift" } ], - "time": "2022-08-12T06:47:24+00:00" + "time": "2023-08-28T11:09:02+00:00" } ], "packages-dev": [ { "name": "composer/pcre", - "version": "3.0.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd" + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/e300eb6c535192decd27a85bc72a9290f0d6b3bd", - "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd", + "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", "shasum": "" }, "require": { @@ -2462,7 +2581,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.0.0" + "source": "https://github.com/composer/pcre/tree/3.1.1" }, "funding": [ { @@ -2478,20 +2597,20 @@ "type": "tidelift" } ], - "time": "2022-02-25T20:21:48+00:00" + "time": "2023-10-11T07:11:09+00:00" }, { "name": "composer/semver", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", "shasum": "" }, "require": { @@ -2541,9 +2660,9 @@ "versioning" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" + "source": "https://github.com/composer/semver/tree/3.4.0" }, "funding": [ { @@ -2559,7 +2678,7 @@ "type": "tidelift" } ], - "time": "2022-04-01T19:23:25+00:00" + "time": "2023-08-31T09:50:34+00:00" }, { "name": "composer/xdebug-handler", @@ -2628,37 +2747,36 @@ "time": "2022-02-25T21:32:43+00:00" }, { - "name": "doctrine/annotations", - "version": "1.13.3", + "name": "doctrine/instantiator", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "648b0343343565c4a056bfc8392201385e8d89f0" + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", - "reference": "648b0343343565c4a056bfc8392201385e8d89f0", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "doctrine/lexer": "1.*", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" + "php": "^8.1" }, "require-dev": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^1.4.10 || ^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2", - "vimeo/psalm": "^4.10" + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2667,226 +2785,1721 @@ ], "authors": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" }, { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" }, { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" } ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.3" - }, - "time": "2022-07-02T10:48:51+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { - "name": "doctrine/lexer", - "version": "1.2.3", + "name": "friendsofphp/php-cs-fixer", + "version": "v3.35.1", "source": { "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "ec1ccc264994b6764882669973ca435cf05bab08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ec1ccc264994b6764882669973ca435cf05bab08", + "reference": "ec1ccc264994b6764882669973ca435cf05bab08", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "composer/semver": "^3.3", + "composer/xdebug-handler": "^3.0.3", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0", + "sebastian/diff": "^4.0 || ^5.0", + "symfony/console": "^5.4 || ^6.0", + "symfony/event-dispatcher": "^5.4 || ^6.0", + "symfony/filesystem": "^5.4 || ^6.0", + "symfony/finder": "^5.4 || ^6.0", + "symfony/options-resolver": "^5.4 || ^6.0", + "symfony/polyfill-mbstring": "^1.27", + "symfony/polyfill-php80": "^1.27", + "symfony/polyfill-php81": "^1.27", + "symfony/process": "^5.4 || ^6.0", + "symfony/stopwatch": "^5.4 || ^6.0" }, "require-dev": { - "doctrine/coding-standard": "^9.0", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.11" - }, - "type": "library", + "facile-it/paraunit": "^1.3 || ^2.0", + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^2.0", + "mikey179/vfsstream": "^1.6.11", + "php-coveralls/php-coveralls": "^2.5.3", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy": "^1.16", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "symfony/phpunit-bridge": "^6.2.3", + "symfony/yaml": "^5.4 || ^6.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "keywords": [ + "Static code analysis", + "fixer", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.35.1" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2023-10-12T13:47:26+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": "v4.17.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, "autoload": { "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + "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/v4.17.1" + }, + "time": "2023-08-13T19:53:39+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "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.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.10.39", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d9dedb0413f678b4d03cbc2279a48f91592c97c4", + "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2023-10-17T15:46:26+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.29", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.15", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "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-master": "9.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 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/9.2.29" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-09-19T04:57:46+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "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", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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": "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/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "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/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.13", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "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": ">=7.3", + "phpunit/php-code-coverage": "^9.2.28", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-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/9.6.13" + }, + "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": "2023-09-19T05:39:22+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.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/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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 calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-05-07T05:35:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bde739e7565280bda77be70044ac1047bc007e34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-02T09:26:13+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.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/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" }, { - "name": "Roman Borschel", - "email": "roman@code-factory.org" + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" }, { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.3" + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" + "url": "https://github.com/sebastianbergmann", + "type": "github" } ], - "time": "2022-02-28T11:07:21+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.9.5", + "name": "sebastian/resource-operations", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "4465d70ba776806857a1ac2a6f877e582445ff36" + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/4465d70ba776806857a1ac2a6f877e582445ff36", - "reference": "4465d70ba776806857a1ac2a6f877e582445ff36", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "composer/semver": "^3.2", - "composer/xdebug-handler": "^3.0.3", - "doctrine/annotations": "^1.13", - "ext-json": "*", - "ext-tokenizer": "*", - "php": "^7.4 || ^8.0", - "php-cs-fixer/diff": "^2.0", - "symfony/console": "^5.4 || ^6.0", - "symfony/event-dispatcher": "^5.4 || ^6.0", - "symfony/filesystem": "^5.4 || ^6.0", - "symfony/finder": "^5.4 || ^6.0", - "symfony/options-resolver": "^5.4 || ^6.0", - "symfony/polyfill-mbstring": "^1.23", - "symfony/polyfill-php80": "^1.25", - "symfony/polyfill-php81": "^1.25", - "symfony/process": "^5.4 || ^6.0", - "symfony/stopwatch": "^5.4 || ^6.0" + "php": ">=7.3" }, "require-dev": { - "justinrainbow/json-schema": "^5.2", - "keradus/cli-executor": "^1.5", - "mikey179/vfsstream": "^1.6.10", - "php-coveralls/php-coveralls": "^2.5.2", - "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", - "phpspec/prophecy": "^1.15", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "phpunitgoodpractices/polyfill": "^1.5", - "phpunitgoodpractices/traits": "^1.9.1", - "symfony/phpunit-bridge": "^6.0", - "symfony/yaml": "^5.4 || ^6.0" + "phpunit/phpunit": "^9.0" }, - "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters." + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "A tool to automatically fix PHP code style", + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.9.5" + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" }, "funding": [ { - "url": "https://github.com/keradus", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2022-07-22T08:43:51+00:00" + "time": "2020-09-28T06:45:17+00:00" }, { - "name": "php-cs-fixer/diff", - "version": "v2.0.2", + "name": "sebastian/type", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/PHP-CS-Fixer/diff.git", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0 || ^8.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", - "symfony/process": "^3.3" + "phpunit/phpunit": "^9.5" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -2899,102 +4512,96 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "sebastian/diff v3 backport support for PHP 5.6+", - "homepage": "https://github.com/PHP-CS-Fixer", - "keywords": [ - "diff" - ], + "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/PHP-CS-Fixer/diff/issues", - "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, - "time": "2020-10-14T08:32:19+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" }, { - "name": "phpstan/phpstan", - "version": "1.8.2", + "name": "sebastian/version", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c53312ecc575caf07b0e90dee43883fdf90ca67c", - "reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" + "php": ">=7.3" }, - "bin": [ - "phpstan", - "phpstan.phar" - ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, "autoload": { - "files": [ - "bootstrap.php" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "PHPStan - PHP Static Analysis Tool", + "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/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.8.2" + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" }, "funding": [ { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2022-07-20T09:57:31+00:00" + "time": "2020-09-28T06:39:44+00:00" }, { "name": "symfony/console", - "version": "v6.1.3", + "version": "v6.3.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "43fcb5c5966b43c56bcfa481368d90d748936ab8" + "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/43fcb5c5966b43c56bcfa481368d90d748936ab8", - "reference": "43fcb5c5966b43c56bcfa481368d90d748936ab8", + "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6", + "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "conflict": { @@ -3016,12 +4623,6 @@ "symfony/process": "^5.4|^6.0", "symfony/var-dumper": "^5.4|^6.0" }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, "type": "library", "autoload": { "psr-4": { @@ -3049,12 +4650,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.1.3" + "source": "https://github.com/symfony/console/tree/v6.3.4" }, "funding": [ { @@ -3070,25 +4671,25 @@ "type": "tidelift" } ], - "time": "2022-07-22T14:17:57+00:00" + "time": "2023-08-16T10:10:12+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.1.0", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4" + "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a3016f5442e28386ded73c43a32a5b68586dd1c4", - "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd", + "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3" + "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -3121,7 +4722,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.1.0" + "source": "https://github.com/symfony/options-resolver/tree/v6.3.0" }, "funding": [ { @@ -3137,36 +4738,41 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2023-05-12T14:21:09+00:00" }, { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.26.0", + "name": "symfony/phpunit-bridge", + "version": "v6.3.6", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "433d05519ce6990bf3530fba6957499d327395c2" + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "c6f1df6a76c2c12bd14a0a5bf7c556dd935efe1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", - "reference": "433d05519ce6990bf3530fba6957499d327395c2", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/c6f1df6a76c2c12bd14a0a5bf7c556dd935efe1d", + "reference": "c6f1df6a76c2c12bd14a0a5bf7c556dd935efe1d", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1.3" }, - "suggest": { - "ext-intl": "For best performance" + "conflict": { + "phpunit/phpunit": "<7.5|9.1.2" }, - "type": "library", + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/polyfill-php81": "^1.27" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", "extra": { - "branch-alias": { - "dev-main": "1.26-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" } }, "autoload": { @@ -3174,8 +4780,11 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3191,18 +4800,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's grapheme_* functions", + "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" + "source": "https://github.com/symfony/phpunit-bridge/tree/v6.3.6" }, "funding": [ { @@ -3218,20 +4819,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-10-12T15:02:41+00:00" }, { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.26.0", + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd" + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "875e90aeea2777b6f135677f618529449334a612" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", + "reference": "875e90aeea2777b6f135677f618529449334a612", "shasum": "" }, "require": { @@ -3243,7 +4844,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3255,11 +4856,8 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "classmap": [ - "Resources/stubs" - ] + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3275,18 +4873,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", + "description": "Symfony polyfill for intl's grapheme_* functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "grapheme", "intl", - "normalizer", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" }, "funding": [ { @@ -3302,29 +4900,32 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.26.0", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { "php": ">=7.1" }, + "suggest": { + "ext-intl": "For best performance" + }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3336,7 +4937,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, "classmap": [ "Resources/stubs" @@ -3347,10 +4948,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -3360,16 +4957,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Symfony polyfill for intl's Normalizer class and related functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "intl", + "normalizer", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" }, "funding": [ { @@ -3385,20 +4984,20 @@ "type": "tidelift" } ], - "time": "2022-05-10T07:21:04+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.26.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", - "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", "shasum": "" }, "require": { @@ -3407,7 +5006,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3448,7 +5047,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" }, "funding": [ { @@ -3464,20 +5063,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/process", - "version": "v6.1.3", + "version": "v6.3.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "a6506e99cfad7059b1ab5cab395854a0a0c21292" + "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/a6506e99cfad7059b1ab5cab395854a0a0c21292", - "reference": "a6506e99cfad7059b1ab5cab395854a0a0c21292", + "url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54", + "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54", "shasum": "" }, "require": { @@ -3509,7 +5108,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.1.3" + "source": "https://github.com/symfony/process/tree/v6.3.4" }, "funding": [ { @@ -3525,25 +5124,25 @@ "type": "tidelift" } ], - "time": "2022-06-27T17:24:16+00:00" + "time": "2023-08-07T10:39:22+00:00" }, { "name": "symfony/stopwatch", - "version": "v6.1.0", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "77dedae82ce2a26e2e9b481855473fc3b3e4e54d" + "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/77dedae82ce2a26e2e9b481855473fc3b3e4e54d", - "reference": "77dedae82ce2a26e2e9b481855473fc3b3e4e54d", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", + "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/service-contracts": "^1|^2|^3" + "symfony/service-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -3571,7 +5170,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.1.0" + "source": "https://github.com/symfony/stopwatch/tree/v6.3.0" }, "funding": [ { @@ -3587,20 +5186,20 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2023-02-16T10:14:28+00:00" }, { "name": "symfony/string", - "version": "v6.1.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b" + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f35241f45c30bcd9046af2bb200a7086f70e1d6b", - "reference": "f35241f45c30bcd9046af2bb200a7086f70e1d6b", + "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339", + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339", "shasum": "" }, "require": { @@ -3611,12 +5210,13 @@ "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/http-client": "^5.4|^6.0", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/intl": "^6.2", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", @@ -3656,7 +5256,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.1.3" + "source": "https://github.com/symfony/string/tree/v6.3.5" }, "funding": [ { @@ -3672,7 +5272,57 @@ "type": "tidelift" } ], - "time": "2022-07-27T15:50:51+00:00" + "time": "2023-09-18T10:38:32+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "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.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" } ], "aliases": [], diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..be3656a --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,34 @@ + + + + + + + + + + + + tests + + + + + + src + + + + + + + + + + diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index 30eed86..86164d3 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -27,7 +27,7 @@ public static function preparePublicDirectory($publicDir) public function load(array $configs, ContainerBuilder $container): void { - $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new YamlFileLoader($container, new FileLocator(\dirname(__DIR__).'/Resources/config')); $loader->load('services.yaml'); $config = $this->processConfiguration( diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 5d4df3f..506e69c 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -8,17 +8,9 @@ services: - "%pentatrion_vite.builds%" - "%pentatrion_vite.throw_on_missing_entry%" - vite.tag_renderer: - class: Pentatrion\ViteBundle\Asset\TagRenderer - arguments: - - default # Default default_build - - [] # Default builds - - "@?event_dispatcher" - Pentatrion\ViteBundle\Asset\EntrypointsLookup: alias: "vite.entrypoints_lookup" - vite.entrypoint_renderer: class: Pentatrion\ViteBundle\Asset\EntrypointRenderer arguments: @@ -30,6 +22,14 @@ services: Pentatrion\ViteBundle\Asset\EntrypointRenderer: alias: "vite.entrypoint_renderer" + vite.tag_renderer: + class: Pentatrion\ViteBundle\Asset\TagRenderer + arguments: + - default # Default default_build + - [] # Default builds + - "@?event_dispatcher" + + vite.twig_entry_files_extension: class: Pentatrion\ViteBundle\Twig\EntryFilesTwigExtension diff --git a/tests/Asset/TagRendererTest.php b/tests/Asset/TagRendererTest.php new file mode 100644 index 0000000..71852f1 --- /dev/null +++ b/tests/Asset/TagRendererTest.php @@ -0,0 +1,13 @@ +assertEquals(1, 1); + } +} From 40cb64e6c4d3ded71809bcf1804493553596c506 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 27 Oct 2023 16:29:50 +0200 Subject: [PATCH 03/19] split EntrypointsLookup and TagRender services by config to reduce complexity --- src/Asset/EntrypointRenderer.php | 120 +++++++------ src/Asset/EntrypointsLookup.php | 113 ++++++------ src/Asset/EntrypointsLookupCollection.php | 33 ++++ src/Asset/TagRenderer.php | 37 ++-- src/Asset/TagRendererCollection.php | 33 ++++ src/DependencyInjection/Configuration.php | 30 ++++ .../PentatrionViteExtension.php | 161 +++++++++++++----- .../UndefinedConfigNameException.php | 7 + src/Resources/config/services.yaml | 67 +++++--- 9 files changed, 389 insertions(+), 212 deletions(-) create mode 100644 src/Asset/EntrypointsLookupCollection.php create mode 100644 src/Asset/TagRendererCollection.php create mode 100644 src/Exception/UndefinedConfigNameException.php diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index 08972e9..68feb82 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -6,10 +6,10 @@ class EntrypointRenderer { - private $entrypointsLookup; - private $tagRenderer; - private $router; - private $useAbsoluteUrl; + private EntrypointsLookupCollection $entrypointsLookupCollection; + private TagRendererCollection $tagRendererCollection; + private bool $useAbsoluteUrl; + private RouterInterface $router; private $returnedViteClients = []; private $returnedReactRefresh = []; @@ -18,63 +18,76 @@ class EntrypointRenderer private $hasReturnedViteLegacyScripts = false; public function __construct( - EntrypointsLookup $entrypointsLookup, - TagRenderer $tagRenderer, + EntrypointsLookupCollection $entrypointsLookupCollection, + TagRendererCollection $tagRendererCollection, bool $useAbsoluteUrl, RouterInterface $router = null ) { - $this->entrypointsLookup = $entrypointsLookup; - $this->tagRenderer = $tagRenderer; + $this->entrypointsLookupCollection = $entrypointsLookupCollection; + $this->tagRendererCollection = $tagRendererCollection; $this->useAbsoluteUrl = $useAbsoluteUrl; $this->router = $router; } - public function renderScripts(string $entryName, array $options = [], $buildName = null): string + private function getEntrypointsLookup(string $configName = null): EntrypointsLookup { - if (!$this->entrypointsLookup->hasFile($buildName)) { + return $this->entrypointsLookupCollection->getEntrypointsLookup($configName); + } + + private function getTagRenderer(string $configName = null): TagRenderer + { + return $this->tagRendererCollection->getTagRenderer($configName); + } + + public function renderScripts(string $entryName, array $options = [], $configName = null): string + { + $entrypointsLookup = $this->getEntrypointsLookup($configName); + $tagRenderer = $this->getTagRenderer($configName); + + if (!$entrypointsLookup->hasFile()) { return ''; } - $useAbsoluteUrl = $this->shouldUseAbsoluteURL($options, $buildName); + $useAbsoluteUrl = $this->shouldUseAbsoluteURL($options, $configName); $content = []; - $viteServer = $this->entrypointsLookup->getViteServer($buildName); - $isBuild = $this->entrypointsLookup->isBuild($buildName); + $viteServer = $entrypointsLookup->getViteServer(); + $isBuild = $entrypointsLookup->isBuild(); if (false !== $viteServer) { // vite server is active - if (!isset($this->returnedViteClients[$buildName])) { - $content[] = $this->tagRenderer->renderTag('script', [ + if (!isset($this->returnedViteClients[$configName])) { + $content[] = $tagRenderer->renderTag('script', [ 'type' => 'module', 'src' => $viteServer['origin'].$viteServer['base'].'@vite/client', ]); - $this->returnedViteClients[$buildName] = true; + $this->returnedViteClients[$configName] = true; } - if (!isset($this->returnedReactRefresh[$buildName]) && isset($options['dependency']) && 'react' === $options['dependency']) { - $content[] = $this->tagRenderer->renderReactRefreshInline($viteServer['origin'].$viteServer['base']); - $this->returnedReactRefresh[$buildName] = true; + if (!isset($this->returnedReactRefresh[$configName]) && isset($options['dependency']) && 'react' === $options['dependency']) { + $content[] = $tagRenderer->renderReactRefreshInline($viteServer['origin'].$viteServer['base']); + $this->returnedReactRefresh[$configName] = true; } } elseif ( - $this->entrypointsLookup->isLegacyPluginEnabled($buildName) + $entrypointsLookup->isLegacyPluginEnabled() && !$this->hasReturnedViteLegacyScripts ) { /* legacy section when vite server is inactive */ /* set or not the __vite_is_modern_browser variable */ - $content[] = $this->tagRenderer::DETECT_MODERN_BROWSER_CODE; + $content[] = $tagRenderer::DETECT_MODERN_BROWSER_CODE; /* if your browser understands the modules but not dynamic import, * load the legacy entrypoints */ - $content[] = $this->tagRenderer::DYNAMIC_FALLBACK_INLINE_CODE; + $content[] = $tagRenderer::DYNAMIC_FALLBACK_INLINE_CODE; /* Safari 10.1 supports modules, but does not support the `nomodule` attribute * it will load '.PHP_EOL; } - public function renderScriptFile($extraAttributes = [], $content = '', $buildName = null, $isBuild = true): string + public function renderScriptFile($extraAttributes = [], $content = '', $isBuild = true): string { - if (is_null($buildName)) { - $buildName = $this->defaultBuild; - } - $event = new RenderAssetTagEvent( RenderAssetTagEvent::TYPE_SCRIPT, - array_merge($this->builds[$buildName]['script_attributes'], $extraAttributes), + array_merge($this->scriptAttributes, $extraAttributes), $isBuild ); if (null !== $this->eventDispatcher) { @@ -82,12 +79,8 @@ public function renderScriptFile($extraAttributes = [], $content = '', $buildNam return $this->renderTag('script', $event->getAttributes(), $content); } - public function renderLinkStylesheet($fileName, $extraAttributes = [], $buildName = null, $isBuild = true): string + public function renderLinkStylesheet($fileName, $extraAttributes = [], $isBuild = true): string { - if (is_null($buildName)) { - $buildName = $this->defaultBuild; - } - $attributes = [ 'rel' => 'stylesheet', 'href' => $fileName, @@ -95,7 +88,7 @@ public function renderLinkStylesheet($fileName, $extraAttributes = [], $buildNam $event = new RenderAssetTagEvent( RenderAssetTagEvent::TYPE_LINK, - array_merge($attributes, $this->builds[$buildName]['link_attributes'], $extraAttributes), + array_merge($attributes, $this->linkAttributes, $extraAttributes), $isBuild ); if (null !== $this->eventDispatcher) { @@ -105,12 +98,8 @@ public function renderLinkStylesheet($fileName, $extraAttributes = [], $buildNam return $this->renderTag('link', $event->getAttributes()); } - public function renderLinkPreload($fileName, $extraAttributes = [], $buildName = null, $isBuild = true): string + public function renderLinkPreload($fileName, $extraAttributes = [], $isBuild = true): string { - if (is_null($buildName)) { - $buildName = $this->defaultBuild; - } - $attributes = [ 'rel' => 'modulepreload', 'href' => $fileName, @@ -118,7 +107,7 @@ public function renderLinkPreload($fileName, $extraAttributes = [], $buildName = $event = new RenderAssetTagEvent( RenderAssetTagEvent::TYPE_PRELOAD, - array_merge($attributes, $this->builds[$buildName]['link_attributes'], $extraAttributes), + array_merge($attributes, $this->linkAttributes, $extraAttributes), $isBuild ); if (null !== $this->eventDispatcher) { diff --git a/src/Asset/TagRendererCollection.php b/src/Asset/TagRendererCollection.php new file mode 100644 index 0000000..ccd6163 --- /dev/null +++ b/src/Asset/TagRendererCollection.php @@ -0,0 +1,33 @@ +tagRendererLocator = $tagRendererLocator; + $this->defaultConfigName = $defaultConfigName; + } + + public function getTagRenderer(string $configName = null): TagRenderer + { + if (is_null($configName)) { + $configName = $this->defaultConfigName; + } + + if (!$this->tagRendererLocator->has($configName)) { + throw new UndefinedConfigNameException(sprintf('The config "%s" is not set.', $configName)); + } + + return $this->tagRendererLocator->get($configName); + } +} diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index ccd665c..ab02df2 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -50,8 +50,38 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->scalarNode('default_build') ->defaultValue(null) + ->setDeprecated('pentatrion/vite-bundle', '6.0.0', 'The "%node%" option is deprecated. Use "default_config" instead.') ->end() ->arrayNode('builds') + ->setDeprecated('pentatrion/vite-bundle', '6.0.0', 'The "%node%" option is deprecated. Use "configs" instead.') + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->scalarNode('build_directory') + ->defaultValue('build') + ->end() + ->arrayNode('script_attributes') + ->info('Key/value pair of attributes to render on all script tags') + ->example('{ defer: true, referrerpolicy: "origin" }') + ->normalizeKeys(false) + ->scalarPrototype() + ->end() + ->end() + ->arrayNode('link_attributes') + ->info('Key/value pair of attributes to render on all CSS link tags') + ->example('{ referrerpolicy: "origin" }') + ->normalizeKeys(false) + ->scalarPrototype() + ->end() + ->end() + ->end() + ->end() + ->end() + ->scalarNode('default_config') + ->defaultValue(null) + ->end() + ->arrayNode('configs') + ->setDeprecated('pentatrion/vite-bundle', '6.0.0', 'The "%node%" option is deprecated. Use "configs" instead.') ->useAttributeAsKey('name') ->arrayPrototype() ->children() diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index 86164d3..6562ec9 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -2,74 +2,141 @@ namespace Pentatrion\ViteBundle\DependencyInjection; +use Pentatrion\ViteBundle\Asset\EntrypointsLookup; +use Pentatrion\ViteBundle\Asset\TagRenderer; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; +use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; class PentatrionViteExtension extends Extension { - public static function prepareBase($base) - { - $base = '/' !== substr($base, 0, 1) ? '/'.$base : $base; - $base = '/' !== substr($base, -1) ? $base.'/' : $base; - - return $base; - } - - public static function preparePublicDirectory($publicDir) - { - $publicDir = '/' !== substr($publicDir, 0, 1) ? '/'.$publicDir : $publicDir; - $publicDir = rtrim($publicDir, '/'); - - return $publicDir; - } - - public function load(array $configs, ContainerBuilder $container): void + public function load(array $bundleConfigs, ContainerBuilder $container): void { $loader = new YamlFileLoader($container, new FileLocator(\dirname(__DIR__).'/Resources/config')); $loader->load('services.yaml'); - $config = $this->processConfiguration( - $this->getConfiguration($configs, $container), - $configs + $bundleConfig = $this->processConfiguration( + $this->getConfiguration($bundleConfigs, $container), + $bundleConfigs ); + if (isset($bundleConfig['builds']) && !isset($bundleConfig['configs'])) { + $bundleConfig['configs'] = $bundleConfig['builds']; + } + if (isset($bundleConfig['default_build']) && !isset($bundleConfig['default_config'])) { + $bundleConfig['default_config'] = $bundleConfig['default_build']; + } + if ( - count($config['builds']) > 0) { - if (is_null($config['default_build']) || !isset($config['builds'][$config['default_build']])) { - throw new \Exception('Invalid default_build, choose between : '.join(', ', array_keys($config['builds']))); + count($bundleConfig['configs']) > 0) { + if (is_null($bundleConfig['default_config']) || !isset($bundleConfig['configs'][$bundleConfig['default_config']])) { + throw new \Exception('Invalid default_config, choose between : '.join(', ', array_keys($bundleConfig['configs']))); } - $defaultBuild = $config['default_build']; - $builds = []; - foreach ($config['builds'] as $buildName => $build) { - $builds[$buildName] = [ - 'base' => self::prepareBase($build['build_directory']), - 'script_attributes' => $build['script_attributes'], - 'link_attributes' => $build['link_attributes'], - ]; + $defaultConfigName = $bundleConfig['default_config']; + $lookupFactories = []; + $tagRendererFactories = []; + $configs = []; + + foreach ($bundleConfig['configs'] as $configName => $config) { + $configs[$configName] = $configPrepared = self::prepareConfig($config); + $lookupFactories[$configName] = $this->entrypointsLookupFactory($container, $configName, $configPrepared); + $tagRendererFactories[$configName] = $this->tagRendererFactory($container, $configName, $configPrepared); } } else { - $defaultBuild = 'default'; - $builds = [ - 'default' => [ - 'base' => self::prepareBase($config['build_directory']), - 'script_attributes' => $config['script_attributes'], - 'link_attributes' => $config['link_attributes'], - ], + $defaultConfigName = '_default'; + $configs[$defaultConfigName] = $configPrepared = self::prepareConfig($bundleConfig); + + $lookupFactories = [ + '_default' => $this->entrypointsLookupFactory($container, $defaultConfigName, $configPrepared), + ]; + $tagRendererFactories = [ + '_default' => $this->tagRendererFactory($container, $defaultConfigName, $configPrepared), ]; } - $container->setParameter('pentatrion_vite.public_directory', self::preparePublicDirectory($config['public_directory'])); - $container->setParameter('pentatrion_vite.default_build', $defaultBuild); - $container->setParameter('pentatrion_vite.builds', $builds); + $container->setParameter('pentatrion_vite.public_directory', self::preparePublicDirectory($bundleConfig['public_directory'])); + $container->setParameter('pentatrion_vite.default_config', $defaultConfigName); + $container->setParameter('pentatrion_vite.configs', $configs); + + $container->setParameter('pentatrion_vite.absolute_url', $bundleConfig['absolute_url']); + $container->setParameter('pentatrion_vite.proxy_origin', $bundleConfig['proxy_origin']); + $container->setParameter('pentatrion_vite.throw_on_missing_entry', $bundleConfig['throw_on_missing_entry']); - $container->setParameter('pentatrion_vite.absolute_url', $config['absolute_url']); - $container->setParameter('pentatrion_vite.proxy_origin', $config['proxy_origin']); - $container->setParameter('pentatrion_vite.throw_on_missing_entry', $config['throw_on_missing_entry']); + $container->getDefinition('pentatrion_vite.entrypoints_lookup_collection') + ->addArgument(ServiceLocatorTagPass::register($container, $lookupFactories)) + ->addArgument($defaultConfigName); - $container->getDefinition('vite.tag_renderer') - ->replaceArgument(0, $defaultBuild) - ->replaceArgument(1, $builds); + $container->getDefinition('pentatrion_vite.tag_renderer_collection') + ->addArgument(ServiceLocatorTagPass::register($container, $tagRendererFactories)) + ->addArgument($defaultConfigName); + + // $container->getDefinition('pentatrion_vite.tag_renderer') + // ->replaceArgument(0, $defaultConfigName) + // ->replaceArgument(1, $configs); + } + + private function entrypointsLookupFactory( + ContainerBuilder $container, + string $configName, + array $config + ): Reference { + $id = $this->getServiceId('entrypoints_lookup', $configName); + $arguments = [ + '%kernel.project_dir%%pentatrion_vite.public_directory%', + $config, + '%pentatrion_vite.throw_on_missing_entry%', + ]; + $definition = new Definition(EntrypointsLookup::class, $arguments); + $container->setDefinition($id, $definition); + + return new Reference($id); + } + + private function tagRendererFactory( + ContainerBuilder $container, + string $configName, + array $config + ): Reference { + $id = $this->getServiceId('tag_renderer', $configName); + $arguments = [ + $config['script_attributes'], + $config['link_attributes'], + new Reference('event_dispatcher', ContainerInterface::NULL_ON_INVALID_REFERENCE), + ]; + $definition = new Definition(TagRenderer::class, $arguments); + $container->setDefinition($id, $definition); + + return new Reference($id); + } + + private function getServiceId(string $prefix, string $configName): string + { + return sprintf('pentatrion_vite.%s[%s]', $prefix, $configName); + } + + public static function prepareConfig(array $config): array + { + $base = $config['build_directory']; + $base = '/' !== substr($base, 0, 1) ? '/'.$base : $base; + $base = '/' !== substr($base, -1) ? $base.'/' : $base; + + return [ + 'base' => $base, + 'script_attributes' => $config['script_attributes'], + 'link_attributes' => $config['link_attributes'], + ]; + } + + public static function preparePublicDirectory($publicDir) + { + $publicDir = '/' !== substr($publicDir, 0, 1) ? '/'.$publicDir : $publicDir; + $publicDir = rtrim($publicDir, '/'); + + return $publicDir; } } diff --git a/src/Exception/UndefinedConfigNameException.php b/src/Exception/UndefinedConfigNameException.php new file mode 100644 index 0000000..31fea71 --- /dev/null +++ b/src/Exception/UndefinedConfigNameException.php @@ -0,0 +1,7 @@ + Date: Mon, 30 Oct 2023 14:10:46 +0100 Subject: [PATCH 04/19] add tag renderer tests --- .phpunit.result.cache | 2 +- src/Asset/EntrypointRenderer.php | 211 ++++++++++-------- src/Asset/EntrypointsLookup.php | 2 +- src/Asset/InlineContent.php | 56 +++++ src/Asset/Tag.php | 84 +++++++ src/Asset/TagRenderer.php | 165 +++++++------- .../PentatrionViteExtension.php | 2 - src/Event/RenderAssetTagEvent.php | 53 +---- src/Resources/config/services.yaml | 2 +- tests/Asset/TagRendererTest.php | 181 ++++++++++++++- tests/fixtures/dynamic-fallback.html | 15 ++ tests/fixtures/entrypoints-app.json | 20 ++ tests/fixtures/modern-browser.html | 1 + tests/fixtures/react-refresh.html | 7 + tests/fixtures/safari-no-module.html | 1 + 15 files changed, 580 insertions(+), 222 deletions(-) create mode 100644 src/Asset/InlineContent.php create mode 100644 src/Asset/Tag.php create mode 100644 tests/fixtures/dynamic-fallback.html create mode 100644 tests/fixtures/entrypoints-app.json create mode 100644 tests/fixtures/modern-browser.html create mode 100644 tests/fixtures/react-refresh.html create mode 100644 tests/fixtures/safari-no-module.html diff --git a/.phpunit.result.cache b/.phpunit.result.cache index 8c20c2c..5afdd76 100644 --- a/.phpunit.result.cache +++ b/.phpunit.result.cache @@ -1 +1 @@ -{"version":1,"defects":[],"times":{"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTagBasic":1.815}} \ No newline at end of file +{"version":1,"defects":{"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTag":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #5":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #1":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #1":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testSpecialTag":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #1":3},"times":{"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTagBasic":2.477,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTagBasic1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTag":0.004,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes":0.004,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #0":0.003,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #2":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #3":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #4":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #5":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithGlobalAttributes with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #2":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testSpecialTag":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #1":0}} \ No newline at end of file diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index 68feb82..5f1b244 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -2,7 +2,9 @@ namespace Pentatrion\ViteBundle\Asset; +use Pentatrion\ViteBundle\Event\RenderAssetTagEvent; use Symfony\Component\Routing\RouterInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class EntrypointRenderer { @@ -10,9 +12,10 @@ class EntrypointRenderer private TagRendererCollection $tagRendererCollection; private bool $useAbsoluteUrl; private RouterInterface $router; + private EventDispatcherInterface $eventDispatcher; - private $returnedViteClients = []; - private $returnedReactRefresh = []; + private $returnedViteClient = false; + private $returnedReactRefresh = false; private $returnedPreloadedScripts = []; private $hasReturnedViteLegacyScripts = false; @@ -21,12 +24,14 @@ public function __construct( EntrypointsLookupCollection $entrypointsLookupCollection, TagRendererCollection $tagRendererCollection, bool $useAbsoluteUrl, - RouterInterface $router = null + RouterInterface $router = null, + EventDispatcherInterface $eventDispatcher = null ) { $this->entrypointsLookupCollection = $entrypointsLookupCollection; $this->tagRendererCollection = $tagRendererCollection; $this->useAbsoluteUrl = $useAbsoluteUrl; $this->router = $router; + $this->eventDispatcher = $eventDispatcher; } private function getEntrypointsLookup(string $configName = null): EntrypointsLookup @@ -39,8 +44,46 @@ private function getTagRenderer(string $configName = null): TagRenderer return $this->tagRendererCollection->getTagRenderer($configName); } - public function renderScripts(string $entryName, array $options = [], $configName = null): string + private function completeURL(string $path, $useAbsoluteUrl = false) + { + if (false === $useAbsoluteUrl || null === $this->router) { + return $path; + } + + return $this->router->getContext()->getScheme().'://'.$this->router->getContext()->getHost().$path; + } + + private function shouldUseAbsoluteURL(array $options, $configName) + { + $viteServer = $this->getEntrypointsLookup($configName)->getViteServer($configName); + + return false === $viteServer && ($this->useAbsoluteUrl || (isset($options['absolute_url']) && true === $options['absolute_url'])); + } + + public function getMode(string $configName = null): ?string + { + $entrypointsLookup = $this->getEntrypointsLookup($configName); + + if (!$entrypointsLookup->hasFile($configName)) { + return null; + } + + return $entrypointsLookup->isBuild() ? 'build' : 'dev'; + } + + public function reset() { + // resets the state of this service + $this->returnedViteClient = false; + $this->returnedReactRefresh = false; + } + + public function renderScripts( + string $entryName, + array $options = [], + $configName = null, + $toString = true + ): string { $entrypointsLookup = $this->getEntrypointsLookup($configName); $tagRenderer = $this->getTagRenderer($configName); @@ -50,97 +93,89 @@ public function renderScripts(string $entryName, array $options = [], $configNam $useAbsoluteUrl = $this->shouldUseAbsoluteURL($options, $configName); - $content = []; + $tags = []; $viteServer = $entrypointsLookup->getViteServer(); $isBuild = $entrypointsLookup->isBuild(); if (false !== $viteServer) { // vite server is active - if (!isset($this->returnedViteClients[$configName])) { - $content[] = $tagRenderer->renderTag('script', [ - 'type' => 'module', - 'src' => $viteServer['origin'].$viteServer['base'].'@vite/client', - ]); - $this->returnedViteClients[$configName] = true; + if (!$this->returnedViteClient) { + $tags[] = $tagRenderer->createViteClientScript($viteServer['origin'].$viteServer['base'].'@vite/client'); + $this->returnedViteClient = true; } - if (!isset($this->returnedReactRefresh[$configName]) && isset($options['dependency']) && 'react' === $options['dependency']) { - $content[] = $tagRenderer->renderReactRefreshInline($viteServer['origin'].$viteServer['base']); - $this->returnedReactRefresh[$configName] = true; + + if ( + !$this->returnedReactRefresh + && isset($options['dependency']) && 'react' === $options['dependency'] + ) { + $tags[] = $tagRenderer->createReactRefreshScript($viteServer['origin'].$viteServer['base']); + + $this->$this->returnedReactRefresh = true; } } elseif ( $entrypointsLookup->isLegacyPluginEnabled() && !$this->hasReturnedViteLegacyScripts ) { /* legacy section when vite server is inactive */ - - /* set or not the __vite_is_modern_browser variable */ - $content[] = $tagRenderer::DETECT_MODERN_BROWSER_CODE; - - /* if your browser understands the modules but not dynamic import, - * load the legacy entrypoints - */ - $content[] = $tagRenderer::DYNAMIC_FALLBACK_INLINE_CODE; - - /* Safari 10.1 supports modules, but does not support the `nomodule` attribute - * it will load + * and the + * if browser accept modules but don't dynamic import or import.meta + */ + public const DYNAMIC_FALLBACK_INLINE_CODE = << {} + window.\$RefreshSig$ = () => (type) => type + window.__vite_plugin_react_preamble_installed__ = true\n + INLINE; + } +} diff --git a/src/Asset/Tag.php b/src/Asset/Tag.php new file mode 100644 index 0000000..bca3c62 --- /dev/null +++ b/src/Asset/Tag.php @@ -0,0 +1,84 @@ +tagName = $tagName; + $this->attributes = $attributes; + $this->content = $content; + $this->internal = $internal; + } + + public function getTagName(): string + { + return $this->tagName; + } + + public function isScriptTag(): bool + { + return self::SCRIPT_TAG === $this->tagName; + } + + public function isLinkTag(): bool + { + return self::LINK_TAG === $this->tagName; + } + + public function getAttributes(): array + { + return $this->attributes; + } + + /** + * @param string $name The attribute name + * @param string|bool $value Value can be "true" to have an attribute without a value (e.g. "defer") + */ + public function setAttribute(string $name, $value): self + { + $this->attributes[$name] = $value; + + return $this; + } + + public function removeAttribute(string $name): self + { + unset($this->attributes[$name]); + + return $this; + } + + public function getContent(): string + { + return $this->content; + } + + public function setContent($content): self + { + $this->content = $content; + + return $this; + } + + public function removeContent(): self + { + $this->content = ''; + + return $this; + } + + public function isInternal(): bool + { + return $this->internal; + } +} diff --git a/src/Asset/TagRenderer.php b/src/Asset/TagRenderer.php index 01feb1f..4d777e8 100644 --- a/src/Asset/TagRenderer.php +++ b/src/Asset/TagRenderer.php @@ -2,130 +2,127 @@ namespace Pentatrion\ViteBundle\Asset; -use Pentatrion\ViteBundle\Event\RenderAssetTagEvent; -use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; - class TagRenderer { - private array $scriptAttributes; - private array $linkAttributes; - - private EventDispatcherInterface $eventDispatcher; - - // https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc - public const SAFARI10_NO_MODULE_FIX = ''; - - public const DETECT_MODERN_BROWSER_CODE = ''; - - // load the - // and the - // if browser accept modules but don't dynamic import or import.meta - public const DYNAMIC_FALLBACK_INLINE_CODE = ' - '; - - public const SYSTEM_JS_INLINE_CODE = 'System.import(document.getElementById("__ID__").getAttribute("data-src"))'; + private array $globalScriptAttributes; + private array $globalLinkAttributes; public function __construct( $scriptAttributes = [], - $linkAttributes = [], - EventDispatcherInterface $eventDispatcher = null + $linkAttributes = [] ) { - $this->scriptAttributes = $scriptAttributes; - $this->linkAttributes = $linkAttributes; - $this->eventDispatcher = $eventDispatcher; + $this->globalScriptAttributes = $scriptAttributes; + $this->globalLinkAttributes = $linkAttributes; + } + + public function createViteClientScript($src): Tag + { + return $this->createInternalScriptTag( + [ + 'type' => 'module', + 'src' => $src, + ] + ); + } + + public function createReactRefreshScript($devServerUrl): Tag + { + return $this->createInternalScriptTag( + ['type' => 'module'], + InlineContent::getReactRefreshInlineCode($devServerUrl) + ); + } + + public function createSafariNoModuleScript(): Tag + { + return $this->createInternalScriptTag( + ['nomodule' => true], + InlineContent::SAFARI10_NO_MODULE_FIX_INLINE_CODE + ); + } + + public function createDynamicFallbackScript(): Tag + { + return $this->createInternalScriptTag( + ['type' => 'module'], + InlineContent::DYNAMIC_FALLBACK_INLINE_CODE + ); } - public function getSystemJSInlineCode($id): string + public function createDetectModernBrowserScript(): Tag { - return str_replace('__ID__', $id, self::SYSTEM_JS_INLINE_CODE); + return $this->createInternalScriptTag( + ['type' => 'module'], + InlineContent::DETECT_MODERN_BROWSER_INLINE_CODE + ); } - public function renderReactRefreshInline($devServerUrl): string + public function createInternalScriptTag($attributes = [], $content = ''): Tag { - return ' '.PHP_EOL; + $tag = new Tag( + Tag::SCRIPT_TAG, + $attributes, + $content, + true + ); + + return $tag; } - public function renderScriptFile($extraAttributes = [], $content = '', $isBuild = true): string + public function createScriptTag($attributes = [], $content = ''): Tag { - $event = new RenderAssetTagEvent( - RenderAssetTagEvent::TYPE_SCRIPT, - array_merge($this->scriptAttributes, $extraAttributes), - $isBuild + $tag = new Tag( + Tag::SCRIPT_TAG, + array_merge($this->globalScriptAttributes, $attributes), + $content ); - if (null !== $this->eventDispatcher) { - $event = $this->eventDispatcher->dispatch($event); - } - return $this->renderTag('script', $event->getAttributes(), $content); + return $tag; } - public function renderLinkStylesheet($fileName, $extraAttributes = [], $isBuild = true): string + public function createLinkStylesheetTag($fileName, $extraAttributes = []): Tag { $attributes = [ 'rel' => 'stylesheet', 'href' => $fileName, ]; - $event = new RenderAssetTagEvent( - RenderAssetTagEvent::TYPE_LINK, - array_merge($attributes, $this->linkAttributes, $extraAttributes), - $isBuild + $tag = new Tag( + Tag::LINK_TAG, + array_merge($this->globalLinkAttributes, $attributes, $extraAttributes) ); - if (null !== $this->eventDispatcher) { - $event = $this->eventDispatcher->dispatch($event); - } - return $this->renderTag('link', $event->getAttributes()); + return $tag; } - public function renderLinkPreload($fileName, $extraAttributes = [], $isBuild = true): string + public function createModulePreloadLinkTag($fileName, $extraAttributes = []): Tag { $attributes = [ 'rel' => 'modulepreload', 'href' => $fileName, ]; - $event = new RenderAssetTagEvent( - RenderAssetTagEvent::TYPE_PRELOAD, - array_merge($attributes, $this->linkAttributes, $extraAttributes), - $isBuild + $tag = new Tag( + Tag::LINK_TAG, + array_merge($attributes, $extraAttributes) ); - if (null !== $this->eventDispatcher) { - $event = $this->eventDispatcher->dispatch($event); - } - return $this->renderTag('link', $attributes); + return $tag; } - public function renderTag($tagName, $attributes, $content = ''): string + public static function generateTag(Tag $tag): string { - return sprintf( + return $tag->isLinkTag() ? sprintf( + '<%s %s>', + $tag->getTagName(), + self::convertArrayToAttributes($tag->getAttributes()) + ) : sprintf( '<%s %s>%s', - $tagName, - self::convertArrayToAttributes($attributes), - $content, - $tagName - ).PHP_EOL; + $tag->getTagName(), + self::convertArrayToAttributes($tag->getAttributes()), + $tag->getContent(), + $tag->getTagName() + ); } private static function convertArrayToAttributes(array $attributes): string @@ -133,7 +130,7 @@ private static function convertArrayToAttributes(array $attributes): string $nonNullAttributes = array_filter( $attributes, function ($value, $key) { - return null !== $value; + return null !== $value && false !== $value; }, ARRAY_FILTER_USE_BOTH ); diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index 6562ec9..6405185 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -7,7 +7,6 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; @@ -106,7 +105,6 @@ private function tagRendererFactory( $arguments = [ $config['script_attributes'], $config['link_attributes'], - new Reference('event_dispatcher', ContainerInterface::NULL_ON_INVALID_REFERENCE), ]; $definition = new Definition(TagRenderer::class, $arguments); $container->setDefinition($id, $definition); diff --git a/src/Event/RenderAssetTagEvent.php b/src/Event/RenderAssetTagEvent.php index 47c72c3..42acce9 100644 --- a/src/Event/RenderAssetTagEvent.php +++ b/src/Event/RenderAssetTagEvent.php @@ -6,62 +6,29 @@ namespace Pentatrion\ViteBundle\Event; +use Pentatrion\ViteBundle\Asset\Tag; + /** * Dispatched each time a script or link tag is rendered. */ final class RenderAssetTagEvent { - public const TYPE_SCRIPT = 'script'; - public const TYPE_LINK = 'link'; - public const TYPE_PRELOAD = 'preload'; - - private string $type; - private array $attributes; - private bool $isBuild; - - public function __construct(string $type, array $attributes, bool $isBuild) - { - $this->type = $type; - $this->attributes = $attributes; - $this->isBuild = $isBuild; - } + private bool $build; + private Tag $tag; - public function isScriptTag(): bool + public function __construct(bool $build, Tag $tag) { - return self::TYPE_SCRIPT === $this->type; - } - - public function isLinkTag(): bool - { - return self::TYPE_LINK === $this->type; - } - - public function isPreloadTag(): bool - { - return self::TYPE_PRELOAD === $this->type; - } - - public function getAttributes(): array - { - return $this->attributes; + $this->build = $build; + $this->tag = $tag; } public function isBuild(): bool { - return $this->isBuild; - } - - /** - * @param string $name The attribute name - * @param string|bool $value Value can be "true" to have an attribute without a value (e.g. "defer") - */ - public function setAttribute(string $name, $value): void - { - $this->attributes[$name] = $value; + return $this->build; } - public function removeAttribute(string $name): void + public function getTag(): Tag { - unset($this->attributes[$name]); + return $this->tag; } } diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 40434ec..d04f74f 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -24,6 +24,7 @@ services: - "@pentatrion_vite.tag_renderer_collection" - "%pentatrion_vite.absolute_url%" - "@?router" + - "@?event_dispatcher" Pentatrion\ViteBundle\Asset\EntrypointRenderer: alias: "pentatrion_vite.entrypoint_renderer" @@ -40,7 +41,6 @@ services: # arguments: # - [] # Default script_attributes # - [] # Default link_attributes - # - "@?event_dispatcher" diff --git a/tests/Asset/TagRendererTest.php b/tests/Asset/TagRendererTest.php index 71852f1..d38fe47 100644 --- a/tests/Asset/TagRendererTest.php +++ b/tests/Asset/TagRendererTest.php @@ -2,12 +2,189 @@ namespace Pentatrion\ViteBundle\Tests\Asset; +use Pentatrion\ViteBundle\Asset\Tag; +use Pentatrion\ViteBundle\Asset\TagRenderer; use PHPUnit\Framework\TestCase; class TagRendererTest extends TestCase { - public function testRenderTagBasic() + public function tag1Provider() { - $this->assertEquals(1, 1); + return [ + [ + new Tag('script', ['src' => '/app.js']), + '', + ], + [ + new Tag('script', ['src' => '/app.js', 'defer' => null]), + '', + ], + [ + new Tag('script', ['src' => '/app.js', 'defer' => false]), + '', + ], + [ + new Tag('script', ['src' => '/app.js', 'async' => true]), + '', + ], + [ + new Tag('script', ['src' => '/app.js'], '[js-content]'), + '', + ], + [ + new Tag('script', ['foo' => 'bar"baz']), + '', + ], + ]; + } + + /** + * @dataProvider tag1Provider + */ + public function testGenerateTagWithCustomAttributes(Tag $tag, string $expectedString) + { + $tagRenderer = new TagRenderer(); + $this->assertEquals($expectedString, $tagRenderer->generateTag($tag)); + } + + public function scriptProvider() + { + return [ + [ + ['src' => '/app.js'], + '', + 'global attribute is added', + ], + [ + ['src' => '/app.js', 'defer' => true], + '', + 'attributes is not repeated', + ], + [ + ['src' => '/app.js', 'defer' => false], + '', + 'local attribute has priority', + ], + ]; + } + + /** + * @dataProvider scriptProvider + */ + public function testGenerateScript(array $attributes, string $expectedString, string $message) + { + $tagRenderer = new TagRenderer( + ['defer' => true], + [] + ); + + $tag = $tagRenderer->createScriptTag($attributes); + + $this->assertEquals($expectedString, $tagRenderer->generateTag($tag), $message); + } + + public function linkStylesheetProvider() + { + return [ + [ + '/style.css', + [], + '', + 'global attribute is added', + ], + [ + '/style.css', + ['referrerpolicy' => 'no-referrer'], + '', + 'local attribute has priority', + ], + ]; + } + + /** + * @dataProvider linkStylesheetProvider + */ + public function testGenerateLinkStylesheet(string $fileName, array $extraAttributes, string $expectedString, string $message) + { + $tagRenderer = new TagRenderer( + [], + ['referrerpolicy' => 'origin'] + ); + + $tag = $tagRenderer->createLinkStylesheetTag($fileName, $extraAttributes); + + $this->assertEquals($expectedString, $tagRenderer->generateTag($tag), $message); + } + + public function linkPreloadProvider() + { + return [ + [ + '/dependency.js', + [], + '', + 'global link/script attribute are not added', + ], + ]; + } + + /** + * @dataProvider linkPreloadProvider + */ + public function testGenerateLinkPreload(string $fileName, array $extraAttributes, string $expectedString, string $message) + { + $tagRenderer = new TagRenderer( + ['defer' => true], + ['referrerpolicy' => 'origin'] + ); + + $tag = $tagRenderer->createModulePreloadLinkTag($fileName, $extraAttributes); + + $this->assertEquals($expectedString, $tagRenderer->generateTag($tag), $message); + } + + public function testSpecialTag() + { + $tagRenderer = new TagRenderer( + ['defer' => true], + ['referrerpolicy' => 'origin'] + ); + + $tag = $tagRenderer->createInternalScriptTag(['src' => '/internal.js']); + $this->assertEquals( + '', + $tagRenderer->generateTag($tag), + 'internal script tag has not global script tags' + ); + + $tag = $tagRenderer->createViteClientScript('http://127.0.0.1:5173/build/@vite/client'); + $this->assertEquals( + '', + $tagRenderer->generateTag($tag) + ); + + $tag = $tagRenderer->createReactRefreshScript('http://127.0.0.1:5173'); + $this->assertEquals( + file_get_contents(__DIR__.'/../fixtures/react-refresh.html'), + $tagRenderer->generateTag($tag) + ); + + $tag = $tagRenderer->createSafariNoModuleScript(); + $this->assertEquals( + file_get_contents(__DIR__.'/../fixtures/safari-no-module.html'), + $tagRenderer->generateTag($tag) + ); + + $tag = $tagRenderer->createDynamicFallbackScript(); + $this->assertEquals( + file_get_contents(__DIR__.'/../fixtures/dynamic-fallback.html'), + $tagRenderer->generateTag($tag) + ); + + $tag = $tagRenderer->createDetectModernBrowserScript(); + $this->assertEquals( + file_get_contents(__DIR__.'/../fixtures/modern-browser.html'), + $tagRenderer->generateTag($tag) + ); } } diff --git a/tests/fixtures/dynamic-fallback.html b/tests/fixtures/dynamic-fallback.html new file mode 100644 index 0000000..2c993fd --- /dev/null +++ b/tests/fixtures/dynamic-fallback.html @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/tests/fixtures/entrypoints-app.json b/tests/fixtures/entrypoints-app.json new file mode 100644 index 0000000..a202822 --- /dev/null +++ b/tests/fixtures/entrypoints-app.json @@ -0,0 +1,20 @@ +{ + "entryPoints": { + "app": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + { + "path": "/build/assets/app-dc399f15.js", + "hash": null + } + ], + "legacy": false, + "preload": [] + } + }, + "isBuild": true, + "legacy": false, + "viteServer": false +} \ No newline at end of file diff --git a/tests/fixtures/modern-browser.html b/tests/fixtures/modern-browser.html new file mode 100644 index 0000000..bed7370 --- /dev/null +++ b/tests/fixtures/modern-browser.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/fixtures/react-refresh.html b/tests/fixtures/react-refresh.html new file mode 100644 index 0000000..011abf2 --- /dev/null +++ b/tests/fixtures/react-refresh.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/tests/fixtures/safari-no-module.html b/tests/fixtures/safari-no-module.html new file mode 100644 index 0000000..2118e26 --- /dev/null +++ b/tests/fixtures/safari-no-module.html @@ -0,0 +1 @@ + \ No newline at end of file From 321507a4664ca1821757e1d65c834aec45e7ff56 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Mon, 30 Oct 2023 16:51:44 +0100 Subject: [PATCH 05/19] add EntrypointsLookup tests --- .gitignore | 3 +- .phpunit.result.cache | 1 - src/Asset/EntrypointRenderer.php | 40 ++-- src/Asset/EntrypointsLookup.php | 21 +- src/Exception/EntrypointNotFoundException.php | 7 + tests/Asset/EntrypointsLookupTest.php | 206 ++++++++++++++++++ tests/Asset/TagRendererTest.php | 2 +- tests/fixtures/entrypoints-app.json | 20 -- .../entrypoints/basic-build/entrypoints.json | 59 +++++ .../entrypoints/basic-dev/entrypoints.json | 20 ++ .../entrypoints/legacy-build/entrypoints.json | 59 +++++ .../metadata-build/entrypoints.json | 21 ++ 12 files changed, 412 insertions(+), 47 deletions(-) delete mode 100644 .phpunit.result.cache create mode 100644 src/Exception/EntrypointNotFoundException.php create mode 100644 tests/Asset/EntrypointsLookupTest.php delete mode 100644 tests/fixtures/entrypoints-app.json create mode 100644 tests/fixtures/entrypoints/basic-build/entrypoints.json create mode 100644 tests/fixtures/entrypoints/basic-dev/entrypoints.json create mode 100644 tests/fixtures/entrypoints/legacy-build/entrypoints.json create mode 100644 tests/fixtures/entrypoints/metadata-build/entrypoints.json diff --git a/.gitignore b/.gitignore index 13c01ef..4e9c2f2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /.local /.idea /vendor -/.php-cs-fixer.cache \ No newline at end of file +/.php-cs-fixer.cache +/.phpunit.result.cache diff --git a/.phpunit.result.cache b/.phpunit.result.cache deleted file mode 100644 index 5afdd76..0000000 --- a/.phpunit.result.cache +++ /dev/null @@ -1 +0,0 @@ -{"version":1,"defects":{"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTag":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #5":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #1":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #1":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testSpecialTag":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #0":3,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #1":3},"times":{"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTagBasic":2.477,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTagBasic1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testRenderTag":0.004,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes":0.004,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #0":0.003,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #2":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #3":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #4":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithCustomAttributes with data set #5":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateTagWithGlobalAttributes with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateScript with data set #2":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkStylesheet with data set #1":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testSpecialTag":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #0":0,"Pentatrion\\ViteBundle\\Tests\\Asset\\TagRendererTest::testGenerateLinkPreload with data set #1":0}} \ No newline at end of file diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index 5f1b244..38b6dfd 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -121,13 +121,13 @@ public function renderScripts( $tags[] = $tagRenderer->createDynamicFallbackScript(); $tags[] = $tagRenderer->createSafariNoModuleScript(); - foreach ($entrypointsLookup->getJSFiles('polyfills-legacy') as $fileWithHash) { + foreach ($entrypointsLookup->getJSFiles('polyfills-legacy') as $filePath) { // normally only one js file $tags[] = $tagRenderer->createScriptTag( [ 'nomodule' => true, 'crossorigin' => true, - 'src' => $this->completeURL($fileWithHash['path'], $useAbsoluteUrl), + 'src' => $this->completeURL($filePath, $useAbsoluteUrl), 'id' => 'vite-legacy-polyfill', ] ); @@ -136,13 +136,13 @@ public function renderScripts( } /* normal js scripts */ - foreach ($entrypointsLookup->getJSFiles($entryName) as $fileWithHash) { + foreach ($entrypointsLookup->getJSFiles($entryName) as $filePath) { $tags[] = $tagRenderer->createScriptTag( array_merge( [ 'type' => 'module', - 'src' => $this->completeURL($fileWithHash['path'], $useAbsoluteUrl), - 'integrity' => $fileWithHash['hash'], + 'src' => $this->completeURL($filePath, $useAbsoluteUrl), + 'integrity' => $entrypointsLookup->getFileHash($filePath), ], $options['attr'] ?? [] ) @@ -157,11 +157,11 @@ public function renderScripts( $tags[] = $tagRenderer->createScriptTag( [ 'nomodule' => true, - 'data-src' => $this->completeURL($file['path'], $useAbsoluteUrl), + 'data-src' => $this->completeURL($file, $useAbsoluteUrl), 'id' => $id, 'crossorigin' => true, 'class' => 'vite-legacy-entry', - 'integrity' => $file['hash'], + 'integrity' => $entrypointsLookup->getFileHash($file), ], InlineContent::getSystemJSInlineCode($id) ); @@ -188,33 +188,33 @@ public function renderLinks( $tags = []; - foreach ($entrypointsLookup->getCSSFiles($entryName) as $fileWithHash) { + foreach ($entrypointsLookup->getCSSFiles($entryName) as $filePath) { $tags[] = $tagRenderer->createLinkStylesheetTag( - $this->completeURL($fileWithHash['path'], $useAbsoluteUrl), - array_merge(['integrity' => $fileWithHash['hash']], $options['attr'] ?? []) + $this->completeURL($filePath, $useAbsoluteUrl), + array_merge(['integrity' => $entrypointsLookup->getFileHash($filePath)], $options['attr'] ?? []) ); } if ($isBuild) { - foreach ($entrypointsLookup->getJavascriptDependencies($entryName) as $fileWithHash) { - if (false === \in_array($fileWithHash['path'], $this->returnedPreloadedScripts, true)) { + foreach ($entrypointsLookup->getJavascriptDependencies($entryName) as $filePath) { + if (false === \in_array($filePath, $this->returnedPreloadedScripts, true)) { $tags[] = $tagRenderer->createModulePreloadLinkTag( - $this->completeURL($fileWithHash['path'], $useAbsoluteUrl), - ['integrity' => $fileWithHash['hash']] + $this->completeURL($filePath, $useAbsoluteUrl), + ['integrity' => $entrypointsLookup->getFileHash($filePath)] ); - $this->returnedPreloadedScripts[] = $fileWithHash['path']; + $this->returnedPreloadedScripts[] = $filePath; } } } if ($isBuild && isset($options['preloadDynamicImports']) && true === $options['preloadDynamicImports']) { - foreach ($entrypointsLookup->getJavascriptDynamicDependencies($entryName) as $fileWithHash) { - if (false === \in_array($fileWithHash['path'], $this->returnedPreloadedScripts, true)) { + foreach ($entrypointsLookup->getJavascriptDynamicDependencies($entryName) as $filePath) { + if (false === \in_array($filePath, $this->returnedPreloadedScripts, true)) { $tags[] = $tagRenderer->createModulePreloadLinkTag( - $this->completeURL($fileWithHash['path'], $useAbsoluteUrl), - ['integrity' => $fileWithHash['hash']] + $this->completeURL($filePath, $useAbsoluteUrl), + ['integrity' => $entrypointsLookup->getFileHash($filePath)] ); - $this->returnedPreloadedScripts[] = $fileWithHash['path']; + $this->returnedPreloadedScripts[] = $filePath; } } } diff --git a/src/Asset/EntrypointsLookup.php b/src/Asset/EntrypointsLookup.php index 0db6964..5ee3472 100644 --- a/src/Asset/EntrypointsLookup.php +++ b/src/Asset/EntrypointsLookup.php @@ -2,6 +2,8 @@ namespace Pentatrion\ViteBundle\Asset; +use Pentatrion\ViteBundle\Exception\EntrypointNotFoundException; + class EntrypointsLookup { private bool $throwOnMissingEntry; @@ -35,8 +37,8 @@ private function getFileContent(): array throw new \Exception('entrypoints.json not found at '.$this->fileInfos['entrypointsPath']); } $content = json_decode(file_get_contents($this->fileInfos['entrypointsPath']), true); - if (!isset($content['isBuild'], $content['entryPoints'], $content['viteServer'])) { - throw new \Exception($this->fileInfos['entrypointsPath'].' : isBuild, entryPoints or viteServer not exists'); + if (!isset($content['entryPoints'], $content['viteServer'])) { + throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints or viteServer not exists'); } $this->fileInfos['content'] = $content; @@ -45,6 +47,17 @@ private function getFileContent(): array return $this->fileInfos['content']; } + public function getFileHash(string $filePath): ?string + { + $infos = $this->getFileContent(); + + if (is_null($infos['metadatas']) || !array_key_exists($filePath, $infos['metadatas'])) { + return null; + } + + return $infos['metadatas'][$filePath]['hash']; + } + public function isLegacyPluginEnabled(): bool { $infos = $this->getFileContent(); @@ -54,7 +67,7 @@ public function isLegacyPluginEnabled(): bool public function isBuild(): bool { - return $this->getFileContent()['isBuild']; + return false === $this->getFileContent()['viteServer']; } public function getViteServer() @@ -119,7 +132,7 @@ private function throwIfEntrypointIsMissing(string $entryName): void if (!array_key_exists($entryName, $this->getFileContent()['entryPoints'])) { $keys = array_keys($this->getFileContent()['entryPoints']); $entryPointKeys = join(', ', array_map(function ($key) { return "'$key'"; }, $keys)); - throw new \Exception("Entry '$entryName' not present in the entrypoints file. Defined entrypoints are $entryPointKeys"); + throw new EntrypointNotFoundException(sprintf("Entry '%s' not present in the entrypoints file. Defined entrypoints are %s", $entryName, $entryPointKeys)); } } } diff --git a/src/Exception/EntrypointNotFoundException.php b/src/Exception/EntrypointNotFoundException.php new file mode 100644 index 0000000..a0b0792 --- /dev/null +++ b/src/Exception/EntrypointNotFoundException.php @@ -0,0 +1,7 @@ + '/'.$prefix.'/'], + true + ); + } + + public function testExtra() + { + $entrypointsLookupFileNotExists = $this->getEntrypointsLookup('not-found'); + $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); + + $this->assertEquals( + false, + $entrypointsLookupFileNotExists->hasFile() + ); + + $this->assertEquals( + true, + $entrypointsLookupBasicBuild->hasFile() + ); + } + + public function testExceptionOnMissingEntry() + { + $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); + $this->expectException(EntrypointNotFoundException::class); + + $entrypointsLookupBasicBuild->getJSFiles('unknown-entrypoint'); + } + + public function testViteServer() + { + $entrypointsLookupBasicDev = $this->getEntrypointsLookup('basic-dev'); + $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); + + $this->assertEquals( + ['origin' => 'http://127.0.0.1:5173', 'base' => '/build/'], + $entrypointsLookupBasicDev->getViteServer() + ); + + $this->assertEquals( + false, + $entrypointsLookupBasicBuild->getViteServer() + ); + + $this->assertEquals( + false, + $entrypointsLookupBasicDev->isBuild() + ); + + $this->assertEquals( + true, + $entrypointsLookupBasicBuild->isBuild() + ); + } + + public function devfilesProvider() + { + return [ + ['app', [ + 'assets' => [], + 'css' => [], + 'dynamic' => [], + 'js' => ['http://127.0.0.1:5173/build/assets/app.js'], + 'preload' => [], + ]], + ['theme', [ + 'assets' => [], + 'css' => ['http://127.0.0.1:5173/build/assets/theme.scss'], + 'dynamic' => [], + 'js' => [], + 'preload' => [], + ]], + ]; + } + + /** + * @dataProvider devfilesProvider + */ + public function testGetDevFiles($entryName, $files) + { + $entrypointsLookupBasicDev = $this->getEntrypointsLookup('basic-dev'); + + $this->assertEquals($files['css'], $entrypointsLookupBasicDev->getCSSFiles($entryName)); + $this->assertEquals($files['dynamic'], $entrypointsLookupBasicDev->getJavascriptDynamicDependencies($entryName)); + $this->assertEquals($files['js'], $entrypointsLookupBasicDev->getJSFiles($entryName)); + $this->assertEquals($files['preload'], $entrypointsLookupBasicDev->getJavascriptDependencies($entryName)); + } + + public function buildfilesProvider() + { + return [ + ['app', [ + 'assets' => [], + 'css' => [], + 'dynamic' => [], + 'js' => ['/build/assets/pageImports-53eb9fd1.js'], + 'preload' => [], + ]], + ['theme', [ + 'assets' => [], + 'css' => ['/build/assets/theme-62617963.css'], + 'dynamic' => [], + 'js' => [], + 'preload' => [], + ]], + ['with-dep', [ + 'assets' => [], + 'css' => ['/build/assets/main-76fa9059.css'], + 'dynamic' => [], + 'js' => ['/build/assets/main-e664f4b5.js'], + 'preload' => ['/build/assets/vue-2d05229a.js', '/build/assets/react-2d05228c.js'], + ]], + ['with-async', [ + 'assets' => [], + 'css' => ['/build/assets/main-76fa9059.css'], + 'dynamic' => ['/build/assets/async-script-12324565.js'], + 'js' => ['/build/assets/main-e664f4b5.js'], + 'preload' => ['/build/assets/vue-2d05229a.js', '/build/assets/react-2d05228c.js'], + ]], + ]; + } + + /** + * @dataProvider buildfilesProvider + */ + public function testGetBuildFiles($entryName, $files) + { + $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); + + $this->assertEquals($files['css'], $entrypointsLookupBasicBuild->getCSSFiles($entryName)); + $this->assertEquals($files['dynamic'], $entrypointsLookupBasicBuild->getJavascriptDynamicDependencies($entryName)); + $this->assertEquals($files['js'], $entrypointsLookupBasicBuild->getJSFiles($entryName)); + $this->assertEquals($files['preload'], $entrypointsLookupBasicBuild->getJavascriptDependencies($entryName)); + } + + public function buildLegacyProvider() + { + return [ + ['app', [ + 'assets' => [], + 'css' => [], + 'dynamic' => [], + 'js' => ['/build/assets/app-23802617.js'], + 'preload' => [], + 'legacy_js' => '/build/assets/app-legacy-59951366.js', + ]], + ['theme', [ + 'assets' => [], + 'css' => ['/build/assets/theme-5cd46aed.css'], + 'dynamic' => [], + 'js' => [], + 'preload' => [], + 'legacy_js' => '/build/assets/theme-legacy-de9eb869.js', + ]], + ]; + } + + /** + * @dataProvider buildLegacyProvider + */ + public function testGetBuildLegacyFiles($entryName, $files) + { + $entrypointsLookupLegacyBuild = $this->getEntrypointsLookup('legacy-build'); + + $this->assertEquals($files['css'], $entrypointsLookupLegacyBuild->getCSSFiles($entryName)); + $this->assertEquals($files['dynamic'], $entrypointsLookupLegacyBuild->getJavascriptDynamicDependencies($entryName)); + $this->assertEquals($files['js'], $entrypointsLookupLegacyBuild->getJSFiles($entryName)); + $this->assertEquals($files['preload'], $entrypointsLookupLegacyBuild->getJavascriptDependencies($entryName)); + $this->assertEquals($files['legacy_js'], $entrypointsLookupLegacyBuild->getLegacyJSFile($entryName)); + } + + public function testHashOfFiles() + { + $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); + $this->assertEquals( + null, + $entrypointsLookupBasicBuild->getFileHash('/build/assets/pageImports-53eb9fd1.js') + ); + + $entrypointsLookupMetadataBuild = $this->getEntrypointsLookup('metadata-build'); + $this->assertEquals( + 'sha256-qABtt8+MbhDq8dts7DSJOnBqCO1QbV2S6zg24ylLkKY=', + $entrypointsLookupMetadataBuild->getFileHash('http://cdn.with-cdn.symfony-vite-dev.localhost/assets/pageVue-bda8ac3b.js') + ); + + $entrypointsLookupMetadataBuild = $this->getEntrypointsLookup('metadata-build'); + $this->assertEquals( + null, + $entrypointsLookupMetadataBuild->getFileHash('/build-file-without-metadata.js') + ); + } +} diff --git a/tests/Asset/TagRendererTest.php b/tests/Asset/TagRendererTest.php index d38fe47..55eed62 100644 --- a/tests/Asset/TagRendererTest.php +++ b/tests/Asset/TagRendererTest.php @@ -123,7 +123,7 @@ public function linkPreloadProvider() '/dependency.js', [], '', - 'global link/script attribute are not added', + 'global link/script attributes are not added', ], ]; } diff --git a/tests/fixtures/entrypoints-app.json b/tests/fixtures/entrypoints-app.json deleted file mode 100644 index a202822..0000000 --- a/tests/fixtures/entrypoints-app.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "entryPoints": { - "app": { - "assets": [], - "css": [], - "dynamic": [], - "js": [ - { - "path": "/build/assets/app-dc399f15.js", - "hash": null - } - ], - "legacy": false, - "preload": [] - } - }, - "isBuild": true, - "legacy": false, - "viteServer": false -} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/basic-build/entrypoints.json b/tests/fixtures/entrypoints/basic-build/entrypoints.json new file mode 100644 index 0000000..799a1ef --- /dev/null +++ b/tests/fixtures/entrypoints/basic-build/entrypoints.json @@ -0,0 +1,59 @@ +{ + "entryPoints": { + "app": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "/build/assets/pageImports-53eb9fd1.js" + ], + "legacy": false, + "preload": [] + }, + "theme": { + "assets": [], + "css": [ + "/build/assets/theme-62617963.css" + ], + "dynamic": [], + "js": [], + "legacy": false, + "preload": [] + }, + "with-dep": { + "assets": [], + "css": [ + "/build/assets/main-76fa9059.css" + ], + "dynamic": [], + "js": [ + "/build/assets/main-e664f4b5.js" + ], + "legacy": false, + "preload": [ + "/build/assets/vue-2d05229a.js", + "/build/assets/react-2d05228c.js" + ] + }, + "with-async": { + "assets": [], + "css": [ + "/build/assets/main-76fa9059.css" + ], + "dynamic": [ + "/build/assets/async-script-12324565.js" + ], + "js": [ + "/build/assets/main-e664f4b5.js" + ], + "legacy": false, + "preload": [ + "/build/assets/vue-2d05229a.js", + "/build/assets/react-2d05228c.js" + ] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": false +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/basic-dev/entrypoints.json b/tests/fixtures/entrypoints/basic-dev/entrypoints.json new file mode 100644 index 0000000..9e27575 --- /dev/null +++ b/tests/fixtures/entrypoints/basic-dev/entrypoints.json @@ -0,0 +1,20 @@ +{ + "entryPoints": { + "app": { + "js": [ + "http://127.0.0.1:5173/build/assets/app.js" + ] + }, + "theme": { + "css": [ + "http://127.0.0.1:5173/build/assets/theme.scss" + ] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": { + "origin": "http://127.0.0.1:5173", + "base": "/build/" + } +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/legacy-build/entrypoints.json b/tests/fixtures/entrypoints/legacy-build/entrypoints.json new file mode 100644 index 0000000..a9dcdb9 --- /dev/null +++ b/tests/fixtures/entrypoints/legacy-build/entrypoints.json @@ -0,0 +1,59 @@ +{ + "entryPoints": { + "app-legacy": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "/build/assets/app-legacy-59951366.js" + ], + "legacy": false, + "preload": [] + }, + "app": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "/build/assets/app-23802617.js" + ], + "legacy": "app-legacy", + "preload": [] + }, + "theme-legacy": { + "assets": [ + "/build/assets/topography-303b8303.svg" + ], + "css": [], + "dynamic": [], + "js": [ + "/build/assets/theme-legacy-de9eb869.js" + ], + "legacy": false, + "preload": [] + }, + "theme": { + "assets": [], + "css": [ + "/build/assets/theme-5cd46aed.css" + ], + "dynamic": [], + "js": [], + "legacy": "theme-legacy", + "preload": [] + }, + "polyfills-legacy": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "/build/assets/polyfills-legacy-40963d34.js" + ], + "legacy": false, + "preload": [] + } + }, + "legacy": true, + "metadatas": {}, + "viteServer": false +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/metadata-build/entrypoints.json b/tests/fixtures/entrypoints/metadata-build/entrypoints.json new file mode 100644 index 0000000..d3aacf6 --- /dev/null +++ b/tests/fixtures/entrypoints/metadata-build/entrypoints.json @@ -0,0 +1,21 @@ +{ + "entryPoints": { + "pageVue": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "http://cdn.with-cdn.symfony-vite-dev.localhost/assets/pageVue-bda8ac3b.js" + ], + "legacy": false, + "preload": [] + } + }, + "legacy": false, + "metadatas": { + "http://cdn.with-cdn.symfony-vite-dev.localhost/assets/pageVue-bda8ac3b.js": { + "hash": "sha256-qABtt8+MbhDq8dts7DSJOnBqCO1QbV2S6zg24ylLkKY=" + } + }, + "viteServer": false +} \ No newline at end of file From 014971c208b6bb3f14fa6dc5b160d522f32b3932 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Tue, 31 Oct 2023 13:23:07 +0100 Subject: [PATCH 06/19] add EntrypointRenderer and TagRenderer tests --- src/Asset/EntrypointRenderer.php | 115 ++-- src/Asset/EntrypointsLookup.php | 14 +- src/Asset/Tag.php | 19 + src/Asset/ViteAssetVersionStrategy.php | 39 +- src/Controller/ViteController.php | 37 +- src/DependencyInjection/Configuration.php | 3 +- tests/Asset/EntrypointRendererTest.php | 619 ++++++++++++++++++ tests/Asset/EntrypointsLookupTest.php | 68 +- .../entrypoints/basic-build/entrypoints.json | 25 +- .../entrypoints/basic-dev/entrypoints.json | 6 +- .../config1-build/entrypoints.json | 28 + .../entrypoints/config1-dev/entrypoints.json | 18 + .../config2-build/entrypoints.json | 28 + .../entrypoints/config2-dev/entrypoints.json | 18 + .../duplication-build/entrypoints.json | 34 + .../duplication-dev/entrypoints.json | 23 + .../entrypoints/legacy-build/entrypoints.json | 15 +- .../metadata-build/entrypoints.json | 11 +- 18 files changed, 970 insertions(+), 150 deletions(-) create mode 100644 tests/Asset/EntrypointRendererTest.php create mode 100644 tests/fixtures/entrypoints/config1-build/entrypoints.json create mode 100644 tests/fixtures/entrypoints/config1-dev/entrypoints.json create mode 100644 tests/fixtures/entrypoints/config2-build/entrypoints.json create mode 100644 tests/fixtures/entrypoints/config2-dev/entrypoints.json create mode 100644 tests/fixtures/entrypoints/duplication-build/entrypoints.json create mode 100644 tests/fixtures/entrypoints/duplication-dev/entrypoints.json diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index 38b6dfd..968fd23 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -11,14 +11,14 @@ class EntrypointRenderer private EntrypointsLookupCollection $entrypointsLookupCollection; private TagRendererCollection $tagRendererCollection; private bool $useAbsoluteUrl; - private RouterInterface $router; - private EventDispatcherInterface $eventDispatcher; + private ?RouterInterface $router; + private ?EventDispatcherInterface $eventDispatcher; - private $returnedViteClient = false; - private $returnedReactRefresh = false; - private $returnedPreloadedScripts = []; + private $returnedViteClients = []; + private $returnedReactRefresh = []; + private $returnedViteLegacyScripts = []; - private $hasReturnedViteLegacyScripts = false; + private $renderedFiles = []; public function __construct( EntrypointsLookupCollection $entrypointsLookupCollection, @@ -57,7 +57,7 @@ private function shouldUseAbsoluteURL(array $options, $configName) { $viteServer = $this->getEntrypointsLookup($configName)->getViteServer($configName); - return false === $viteServer && ($this->useAbsoluteUrl || (isset($options['absolute_url']) && true === $options['absolute_url'])); + return is_null($viteServer) && ($this->useAbsoluteUrl || (isset($options['absolute_url']) && true === $options['absolute_url'])); } public function getMode(string $configName = null): ?string @@ -73,9 +73,10 @@ public function getMode(string $configName = null): ?string public function reset() { - // resets the state of this service - $this->returnedViteClient = false; - $this->returnedReactRefresh = false; + $this->returnedViteClients = []; + $this->returnedReactRefresh = []; + $this->returnedViteLegacyScripts = []; + $this->renderedFiles = []; } public function renderScripts( @@ -96,25 +97,27 @@ public function renderScripts( $tags = []; $viteServer = $entrypointsLookup->getViteServer(); $isBuild = $entrypointsLookup->isBuild(); + $base = $entrypointsLookup->getBase(); - if (false !== $viteServer) { + if (!is_null($viteServer)) { // vite server is active - if (!$this->returnedViteClient) { - $tags[] = $tagRenderer->createViteClientScript($viteServer['origin'].$viteServer['base'].'@vite/client'); - $this->returnedViteClient = true; + if (!isset($this->returnedViteClients[$configName])) { + $tags[] = $tagRenderer->createViteClientScript($viteServer.$base.'@vite/client'); + + $this->returnedViteClients[$configName] = true; } if ( - !$this->returnedReactRefresh + !isset($this->returnedReactRefresh[$configName]) && isset($options['dependency']) && 'react' === $options['dependency'] ) { - $tags[] = $tagRenderer->createReactRefreshScript($viteServer['origin'].$viteServer['base']); + $tags[] = $tagRenderer->createReactRefreshScript($viteServer.$base); - $this->$this->returnedReactRefresh = true; + $this->returnedReactRefresh[$configName] = true; } } elseif ( $entrypointsLookup->isLegacyPluginEnabled() - && !$this->hasReturnedViteLegacyScripts + && !isset($this->returnedViteLegacyScripts[$configName]) ) { /* legacy section when vite server is inactive */ $tags[] = $tagRenderer->createDetectModernBrowserScript(); @@ -132,39 +135,48 @@ public function renderScripts( ] ); } - $this->hasReturnedViteLegacyScripts = true; + + $this->returnedViteLegacyScripts[$configName] = true; } /* normal js scripts */ foreach ($entrypointsLookup->getJSFiles($entryName) as $filePath) { - $tags[] = $tagRenderer->createScriptTag( - array_merge( - [ - 'type' => 'module', - 'src' => $this->completeURL($filePath, $useAbsoluteUrl), - 'integrity' => $entrypointsLookup->getFileHash($filePath), - ], - $options['attr'] ?? [] - ) - ); + if (false === \in_array($filePath, $this->renderedFiles, true)) { + $tags[] = $tagRenderer->createScriptTag( + array_merge( + [ + 'type' => 'module', + 'src' => $this->completeURL($filePath, $useAbsoluteUrl), + 'integrity' => $entrypointsLookup->getFileHash($filePath), + ], + $options['attr'] ?? [] + ) + ); + + $this->renderedFiles[] = $filePath; + } } /* legacy js scripts */ if ($entrypointsLookup->hasLegacy($entryName)) { $id = self::pascalToKebab("vite-legacy-entry-$entryName"); - $file = $entrypointsLookup->getLegacyJSFile($entryName); - $tags[] = $tagRenderer->createScriptTag( - [ - 'nomodule' => true, - 'data-src' => $this->completeURL($file, $useAbsoluteUrl), - 'id' => $id, - 'crossorigin' => true, - 'class' => 'vite-legacy-entry', - 'integrity' => $entrypointsLookup->getFileHash($file), - ], - InlineContent::getSystemJSInlineCode($id) - ); + $filePath = $entrypointsLookup->getLegacyJSFile($entryName); + if (false === \in_array($filePath, $this->renderedFiles, true)) { + $tags[] = $tagRenderer->createScriptTag( + [ + 'nomodule' => true, + 'data-src' => $this->completeURL($filePath, $useAbsoluteUrl), + 'id' => $id, + 'crossorigin' => true, + 'class' => 'vite-legacy-entry', + 'integrity' => $entrypointsLookup->getFileHash($filePath), + ], + InlineContent::getSystemJSInlineCode($id) + ); + + $this->renderedFiles[] = $filePath; + } } return $this->renderTags($tags, $isBuild, $toString); @@ -189,32 +201,35 @@ public function renderLinks( $tags = []; foreach ($entrypointsLookup->getCSSFiles($entryName) as $filePath) { - $tags[] = $tagRenderer->createLinkStylesheetTag( - $this->completeURL($filePath, $useAbsoluteUrl), - array_merge(['integrity' => $entrypointsLookup->getFileHash($filePath)], $options['attr'] ?? []) - ); + if (false === \in_array($filePath, $this->renderedFiles, true)) { + $tags[] = $tagRenderer->createLinkStylesheetTag( + $this->completeURL($filePath, $useAbsoluteUrl), + array_merge(['integrity' => $entrypointsLookup->getFileHash($filePath)], $options['attr'] ?? []) + ); + $this->renderedFiles[] = $filePath; + } } if ($isBuild) { foreach ($entrypointsLookup->getJavascriptDependencies($entryName) as $filePath) { - if (false === \in_array($filePath, $this->returnedPreloadedScripts, true)) { + if (false === \in_array($filePath, $this->renderedFiles, true)) { $tags[] = $tagRenderer->createModulePreloadLinkTag( $this->completeURL($filePath, $useAbsoluteUrl), ['integrity' => $entrypointsLookup->getFileHash($filePath)] ); - $this->returnedPreloadedScripts[] = $filePath; + $this->renderedFiles[] = $filePath; } } } if ($isBuild && isset($options['preloadDynamicImports']) && true === $options['preloadDynamicImports']) { foreach ($entrypointsLookup->getJavascriptDynamicDependencies($entryName) as $filePath) { - if (false === \in_array($filePath, $this->returnedPreloadedScripts, true)) { + if (false === \in_array($filePath, $this->renderedFiles, true)) { $tags[] = $tagRenderer->createModulePreloadLinkTag( $this->completeURL($filePath, $useAbsoluteUrl), ['integrity' => $entrypointsLookup->getFileHash($filePath)] ); - $this->returnedPreloadedScripts[] = $filePath; + $this->renderedFiles[] = $filePath; } } } @@ -231,7 +246,7 @@ public function renderTags(array $tags, $isBuild, $toString) } return $toString - ? implode(PHP_EOL, array_map(function ($tagEvent) { + ? implode('', array_map(function ($tagEvent) { return TagRenderer::generateTag($tagEvent); }, $tags)) : $tags; diff --git a/src/Asset/EntrypointsLookup.php b/src/Asset/EntrypointsLookup.php index 5ee3472..174295f 100644 --- a/src/Asset/EntrypointsLookup.php +++ b/src/Asset/EntrypointsLookup.php @@ -37,8 +37,11 @@ private function getFileContent(): array throw new \Exception('entrypoints.json not found at '.$this->fileInfos['entrypointsPath']); } $content = json_decode(file_get_contents($this->fileInfos['entrypointsPath']), true); - if (!isset($content['entryPoints'], $content['viteServer'])) { - throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints or viteServer not exists'); + if (!array_key_exists('entryPoints', $content) + || !array_key_exists('viteServer', $content) + || !array_key_exists('base', $content) + ) { + throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints, base or viteServer not exists'); } $this->fileInfos['content'] = $content; @@ -67,7 +70,7 @@ public function isLegacyPluginEnabled(): bool public function isBuild(): bool { - return false === $this->getFileContent()['viteServer']; + return null === $this->getFileContent()['viteServer']; } public function getViteServer() @@ -75,6 +78,11 @@ public function getViteServer() return $this->getFileContent()['viteServer']; } + public function getBase() + { + return $this->getFileContent()['base']; + } + public function getJSFiles($entryName): array { $this->throwIfEntrypointIsMissing($entryName); diff --git a/src/Asset/Tag.php b/src/Asset/Tag.php index bca3c62..1ea37a0 100644 --- a/src/Asset/Tag.php +++ b/src/Asset/Tag.php @@ -35,11 +35,30 @@ public function isLinkTag(): bool return self::LINK_TAG === $this->tagName; } + public function isStylesheet(): bool + { + return self::LINK_TAG === $this->tagName + && isset($this->attributes['rel']) + && 'stylesheet' === $this->attributes['rel']; + } + + public function isModulePreload(): bool + { + return self::LINK_TAG === $this->tagName + && isset($this->attributes['rel']) + && 'modulepreload' === $this->attributes['rel']; + } + public function getAttributes(): array { return $this->attributes; } + public function getAttribute($key): mixed + { + return key_exists($key, $this->attributes) ? $this->attributes[$key] : null; + } + /** * @param string $name The attribute name * @param string|bool $value Value can be "true" to have an attribute without a value (e.g. "defer") diff --git a/src/Asset/ViteAssetVersionStrategy.php b/src/Asset/ViteAssetVersionStrategy.php index eea7f65..8815268 100644 --- a/src/Asset/ViteAssetVersionStrategy.php +++ b/src/Asset/ViteAssetVersionStrategy.php @@ -10,7 +10,7 @@ class ViteAssetVersionStrategy implements VersionStrategyInterface { private string $publicPath; - private array $builds; + private array $configs; private $useAbsoluteUrl; private $router; @@ -18,41 +18,44 @@ class ViteAssetVersionStrategy implements VersionStrategyInterface private string $entrypointsPath; private $manifestData; private $entrypointsData; - private ?array $build = null; + private ?array $config = null; private bool $strictMode; + private ?string $mode = null; public function __construct( string $publicPath, - array $builds, - string $defaultBuildName, + array $configs, + string $defaultConfigName, bool $useAbsoluteUrl, RouterInterface $router = null, bool $strictMode = true ) { $this->publicPath = $publicPath; - $this->builds = $builds; + $this->configs = $configs; $this->strictMode = $strictMode; $this->useAbsoluteUrl = $useAbsoluteUrl; $this->router = $router; - $this->setBuildName($defaultBuildName); + $this->setConfig($defaultConfigName); if (($scheme = parse_url($this->manifestPath, \PHP_URL_SCHEME)) && 0 === strpos($scheme, 'http')) { throw new \Exception('You can\'t use a remote manifest with ViteAssetVersionStrategy'); } } - public function setBuildName(string $buildName): void + public function setConfig(string $configName): void { - $this->build = $this->builds[$buildName]; - $this->manifestPath = $this->publicPath.$this->build['base'].'manifest.json'; - $this->entrypointsPath = $this->publicPath.$this->build['base'].'entrypoints.json'; + $this->mode = null; + $this->config = $this->configs[$configName]; + $this->manifestPath = $this->publicPath.$this->config['base'].'manifest.json'; + $this->entrypointsPath = $this->publicPath.$this->config['base'].'entrypoints.json'; } /** * With a entrypoints, we don't really know or care about what * the version is. Instead, this returns the path to the - * versioned file. + * versioned file. as it contains a hashed and different path + * with each new config, this is enough for us. */ public function getVersion(string $path): string { @@ -75,19 +78,21 @@ private function completeURL(string $path) private function getassetsPath(string $path): ?string { - if (null === $this->manifestData) { + if (null === $this->mode) { if (!is_file($this->entrypointsPath)) { - throw new RuntimeException(sprintf('assets entrypoints file "%s" does not exist. Did you forget configure your base in pentatrion_vite.yml?', $this->manifestPath)); + throw new RuntimeException(sprintf('assets entrypoints file "%s" does not exist. Did you forget configure your `build_dir` in pentatrion_vite.yml?', $this->entrypointsPath)); } if (is_file($this->manifestPath)) { + // when vite server is running manifest file doesn't exists + $this->mode = 'build'; try { $this->manifestData = json_decode(file_get_contents($this->manifestPath), true, 512, \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $this->manifestPath).$e->getMessage(), 0, $e); } } else { - $this->manifestData = false; + $this->mode = 'dev'; try { $this->entrypointsData = json_decode(file_get_contents($this->entrypointsPath), true, 512, \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { @@ -96,12 +101,12 @@ private function getassetsPath(string $path): ?string } } - if (false !== $this->manifestData) { + if ('build' === $this->mode) { if (isset($this->manifestData[$path])) { - return $this->completeURL($this->build['base'].$this->manifestData[$path]['file']); + return $this->completeURL($this->config['base'].$this->manifestData[$path]['file']); } } else { - return $this->entrypointsData['viteServer']['origin'].$this->entrypointsData['viteServer']['base'].$path; + return $this->entrypointsData['viteServer'].$this->entrypointsData['base'].$path; } if ($this->strictMode) { diff --git a/src/Controller/ViteController.php b/src/Controller/ViteController.php index 8766927..3a5d378 100644 --- a/src/Controller/ViteController.php +++ b/src/Controller/ViteController.php @@ -2,50 +2,53 @@ namespace Pentatrion\ViteBundle\Controller; -use Pentatrion\ViteBundle\Asset\EntrypointsLookup; +use Pentatrion\ViteBundle\Asset\EntrypointsLookupCollection; use Symfony\Component\HttpFoundation\Response; use Symfony\Contracts\HttpClient\HttpClientInterface; class ViteController { public $httpClient; - public string $defaultBuild; - public array $builds; - private $entrypointsLookup; + public string $defaultConfig; + public array $configs; + private $entrypointsLookupCollection; private $proxyOrigin; public function __construct( - string $defaultBuild, - array $builds, + string $defaultConfig, + array $configs, HttpClientInterface $httpClient, - EntrypointsLookup $entrypointsLookup, + EntrypointsLookupCollection $entrypointsLookupCollection, ?string $proxyOrigin ) { - $this->defaultBuild = $defaultBuild; - $this->builds = $builds; + $this->defaultConfig = $defaultConfig; + $this->configs = $configs; $this->httpClient = $httpClient; - $this->entrypointsLookup = $entrypointsLookup; + $this->entrypointsLookupCollection = $entrypointsLookupCollection; $this->proxyOrigin = $proxyOrigin; } - public function proxyBuild($path, $buildName = null): Response + public function proxyBuild($path, $configName = null): Response { - if (is_null($buildName)) { - $buildName = $this->defaultBuild; + if (is_null($configName)) { + $configName = $this->defaultConfig; } - $viteDevServer = $this->entrypointsLookup->getViteServer($buildName); + $entrypointsLookup = $this->entrypointsLookupCollection->getEntrypointsLookup($configName); - if (is_null($viteDevServer) || false === $viteDevServer) { + $viteDevServer = $entrypointsLookup->getViteServer(); + $base = $entrypointsLookup->getBase(); + + if (is_null($viteDevServer)) { return new \Exception('Vite dev server not available'); } - $origin = $this->proxyOrigin ?? $viteDevServer['origin']; + $origin = $this->proxyOrigin ?? $viteDevServer; $response = $this->httpClient->request( 'GET', - $origin.$this->builds[$buildName]['base'].$path + $origin.$base.$path ); $content = $response->getContent(); diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index ab02df2..8ebec11 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -17,9 +17,10 @@ public function getConfigTreeBuilder(): TreeBuilder $rootNode ->children() ->scalarNode('public_directory') - ->defaultValue('public') + ->defaultValue('public') ->end() ->scalarNode('build_directory') + ->info('we only need build_directory to locate entrypoints.json file, it\'s the "base" vite config parameter without slashes.') ->defaultValue('build') ->end() ->scalarNode('proxy_origin') diff --git a/tests/Asset/EntrypointRendererTest.php b/tests/Asset/EntrypointRendererTest.php new file mode 100644 index 0000000..fff2520 --- /dev/null +++ b/tests/Asset/EntrypointRendererTest.php @@ -0,0 +1,619 @@ +createStub(TagRendererCollection::class); + $tagRendererCollection + ->method('getTagRenderer') + ->willReturn($tagRenderer); + + return $tagRendererCollection; + } + + private function getEntrypointsLookupCollection(EntrypointsLookup $entrypointsLookup) + { + /** + * @var EntrypointsLookupCollection|Stub $entrypointsLookupCollection + */ + $entrypointsLookupCollection = $this->createStub(EntrypointsLookupCollection::class); + $entrypointsLookupCollection + ->method('getEntrypointsLookup') + ->willReturn($entrypointsLookup); + + return $entrypointsLookupCollection; + } + + // public function getBaseDevEntrypointsLookupStub() + // { + // /** + // * @var EntrypointsLookup|Stub $entrypointsLookup + // */ + // $entrypointsLookup = $this->createStub(EntrypointsLookup::class); + + // $entrypointsLookup + // ->method('hasFile') + // ->willReturn(true); + + // $entrypointsLookup + // ->method('isBuild') + // ->willReturn(false); + + // $entrypointsLookup + // ->method('getViteServer') + // ->willReturn([ + // 'origin' => 'http://127.0.0.1:5173', + // 'base' => '/build/', + // ]); + + // return $entrypointsLookup; + // } + + // public function getBaseBuildEntrypointsLookupStub() + // { + // /** + // * @var EntrypointsLookup|Stub $entrypointsLookup + // */ + // $entrypointsLookup = $this->createStub(EntrypointsLookup::class); + + // $entrypointsLookup + // ->method('hasFile') + // ->willReturn(true); + + // $entrypointsLookup + // ->method('isBuild') + // ->willReturn(true); + + // $entrypointsLookup + // ->method('getViteServer') + // ->willReturn(false); + + // return $entrypointsLookup; + // } + + private function getEntrypointsLookup($prefix) + { + return new EntrypointsLookup( + __DIR__.'/../fixtures/entrypoints', + ['base' => '/'.$prefix.'/'], + true + ); + } + + public function basicProvider() + { + return [ + [ + 'basic-build', + 'app', + [ + 'mode' => 'build', + 'scripts' => '', + 'links' => '', + ], + ], + [ + 'basic-build', + 'theme', + [ + 'mode' => 'build', + 'scripts' => '', + 'links' => '', + ], + ], + [ + 'basic-build', + 'with-dep', + [ + 'mode' => 'build', + 'scripts' => '', + 'links' => '' + .'' + .'', + ], + ], + [ + 'basic-build', + 'with-async', + [ + 'mode' => 'build', + 'scripts' => '', + 'links' => '' + .'' + .'', + ], + ], + [ + 'basic-dev', + 'app', + [ + 'mode' => 'dev', + 'scripts' => '' + .'', + 'links' => '', + ], + ], + [ + 'basic-dev', + 'theme', + [ + 'mode' => 'dev', + 'scripts' => '', + 'links' => '', + ], + ], + [ + 'legacy-build', + 'app', + [ + 'mode' => 'build', + 'scripts' => '' + .'' + .'' + .'' + .'' + .'', + 'links' => '', + ], + ], + [ + 'legacy-build', + 'theme', + [ + 'mode' => 'build', + 'scripts' => '' + .'' + .'' + .'' + .'', + 'links' => '', + ], + ], + [ + 'metadata-build', + 'app', + [ + 'mode' => 'build', + 'scripts' => '', + 'links' => '', + ], + ], + ]; + } + + /** + * @dataProvider basicProvider + */ + public function testBasic($config, $entryName, $expectedStrings) + { + $entrypointsLookup = $this->getEntrypointsLookup($config); + + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(), + false, + null, + null, + ); + + $this->assertEquals( + $expectedStrings['mode'], + $entrypointRenderer->getMode() + ); + + $this->assertEquals( + $expectedStrings['scripts'], + $entrypointRenderer->renderScripts($entryName) + ); + + $this->assertEquals( + $expectedStrings['links'], + $entrypointRenderer->renderLinks($entryName) + ); + } + + public function testRenderOnlyOneViteClient() + { + $entrypointsLookup = $this->getEntrypointsLookup('duplication-dev'); + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(), + false, + null, + null, + ); + + $this->assertEquals( + '' + .'' + .'', + $entrypointRenderer->renderScripts('app').$entrypointRenderer->renderScripts('other-app') + ); + } + + public function testRenderOnlyOneReactRefresh() + { + $entrypointsLookup = $this->getEntrypointsLookup('duplication-dev'); + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(), + false, + null, + null, + ); + + $this->assertEquals( + '' + .'' + .'' + .'', + $entrypointRenderer->renderScripts('app', ['dependency' => 'react']).$entrypointRenderer->renderScripts('other-app', ['dependency' => 'react']) + ); + } + + public function testRenderOnlyOneFile() + { + $entrypointsLookup = $this->getEntrypointsLookup('duplication-build'); + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(), + false, + null, + null, + ); + + $expectedScripts = '' + .''; + $expectedLinks = '' + .''; + + $this->assertEquals( + $expectedScripts, + $entrypointRenderer->renderScripts('app-1').$entrypointRenderer->renderScripts('app-2') + ); + + $this->assertEquals( + $expectedLinks, + $entrypointRenderer->renderLinks('app-1').$entrypointRenderer->renderLinks('app-2'), + 'dont render twice vuejs dependency' + ); + + $this->assertEquals( + '', + $entrypointRenderer->renderScripts('app-1').$entrypointRenderer->renderScripts('app-2') + ); + + $this->assertEquals( + '', + $entrypointRenderer->renderLinks('app-1').$entrypointRenderer->renderLinks('app-2') + ); + + $entrypointRenderer->reset(); + + $this->assertEquals( + $expectedScripts, + $entrypointRenderer->renderScripts('app-1').$entrypointRenderer->renderScripts('app-2') + ); + + $this->assertEquals( + $expectedLinks, + $entrypointRenderer->renderLinks('app-1').$entrypointRenderer->renderLinks('app-2'), + 'dont render twice vuejs dependency' + ); + } + + public function testRenderOnlyOneLegacyInlineContent() + { + $entrypointsLookup = $this->getEntrypointsLookup('legacy-build'); + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(), + false, + null, + null, + ); + + $this->assertEquals( + '' + .'' + .'' + .'' + .'' + .'' + .'', + $entrypointRenderer->renderScripts('app').$entrypointRenderer->renderScripts('theme') + ); + + $this->assertEquals( + '', + $entrypointRenderer->renderLinks('app').$entrypointRenderer->renderLinks('theme') + ); + } + + public function testRenderWithAbsoluteUrl() + { + /** + * @var Stub|RequestContext $context + */ + $context = $this->createStub(RequestContext::class); + $context + ->method('getScheme') + ->willReturn('http'); + + $context + ->method('getHost') + ->willReturn('mydomain.local'); + /** + * @var Stub|RouterInterface $router + */ + $router = $this->createStub(RouterInterface::class); + $router + ->method('getContext') + ->willReturn($context); + + $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); + $entrypointsLookupBasicDev = $this->getEntrypointsLookup('basic-dev'); + + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookupBasicBuild), + $this->getBasicTagRendererCollection(), + true, + $router, + null, + ); + $this->assertEquals( + '', + $entrypointRenderer->renderScripts('app'), + 'render complete url when absolute_url defined globally' + ); + + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookupBasicBuild), + $this->getBasicTagRendererCollection(), + false, + $router, + null, + ); + $this->assertEquals( + '', + $entrypointRenderer->renderScripts('app', ['absolute_url' => true]), + 'render complete url when absolute_url defined locally' + ); + + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookupBasicDev), + $this->getBasicTagRendererCollection(), + true, + $router, + null, + ); + $this->assertEquals( + '', + $entrypointRenderer->renderScripts('app'), + 'render correct url when absolute_url defined and vite dev server is started' + ); + } + + public function testRenderAndPreloadDynamicImports() + { + $entrypointsLookup = $this->getEntrypointsLookup('basic-build'); + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(), + false, + null, + null, + ); + + $this->assertEquals( + '', + $entrypointRenderer->renderScripts('with-async', [ + 'preloadDynamicImports' => true, + ]) + ); + + $this->assertEquals( + '' + .'' + .'' + .'', + $entrypointRenderer->renderLinks('with-async', [ + 'preloadDynamicImports' => true, + ]), + 'render css files, preload preload&dynamic files' + ); + } + + public function testRenderWithEvent() + { + /** + * @var EventDispatcherInterface|Stub $dispatcher + */ + $dispatcher = $this->createStub(EventDispatcherInterface::class); + $dispatcher + ->method('dispatch') + ->willReturnCallback(function (RenderAssetTagEvent $evt) { + $tag = $evt->getTag(); + if ($tag->isScriptTag()) { + $tag->setAttribute('src', $tag->getAttribute('src').'-modified'); + $tag->setAttribute('nonce', 'custom-nonce'); + } elseif ($tag->isStylesheet()) { + $tag->removeAttribute('referrerpolicy'); + } elseif ($tag->isModulePreload()) { + $tag->setAttribute('data-foo', 'bar'); + } + + return $evt; + }); + + $entrypointsLookup = $this->getEntrypointsLookup('basic-build'); + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(['defer' => true], ['referrerpolicy' => 'origin']), + false, + null, + $dispatcher, + ); + + $this->assertSame( + '', + $entrypointRenderer->renderScripts('app'), + 'filter script, add custom attribute, modify attributes in last' + ); + $this->assertSame( + '', + $entrypointRenderer->renderLinks('theme'), + 'filter stylesheet, remove attribute' + ); + $this->assertSame( + '' + .'' + .'', + $entrypointRenderer->renderLinks('with-dep'), + 'filter modulepreload, add custom attribute' + ); + } + + public function testMultipleConfigInBuild() + { + $entrypointsLookupConfig1 = $this->getEntrypointsLookup('config1-build'); + $entrypointsLookupConfig2 = $this->getEntrypointsLookup('config2-build'); + + /** + * @var EntrypointsLookupCollection|Stub $entrypointsLookupCollection + */ + $entrypointsLookupCollection = $this->createStub(EntrypointsLookupCollection::class); + $entrypointsLookupCollection + ->method('getEntrypointsLookup') + ->will($this->returnValueMap([ + ['config1-dev', $entrypointsLookupConfig1], + ['config2-dev', $entrypointsLookupConfig2], + ])); + + $tagRendererConfig1 = new TagRenderer([], []); + $tagRendererConfig2 = new TagRenderer(['defer' => true], ['referrerpolicy' => 'origin']); + + /** + * @var TagRendererCollection|Stub $tagRendererCollection + */ + $tagRendererCollection = $this->createStub(TagRendererCollection::class); + $tagRendererCollection + ->method('getTagRenderer') + ->will($this->returnValueMap([ + ['config1-dev', $tagRendererConfig1], + ['config2-dev', $tagRendererConfig2], + ])); + + $entrypointRenderer = new EntrypointRenderer( + $entrypointsLookupCollection, + $tagRendererCollection, + false, + null, + null, + ); + + $this->assertEquals( + '' + .'', + $entrypointRenderer->renderScripts('app-1', [], 'config1-dev') + .$entrypointRenderer->renderScripts('app-2', [], 'config2-dev'), + 'render correct global script attributes' + ); + + $this->assertEquals( + '' + .'', + $entrypointRenderer->renderLinks('theme-1', [], 'config1-dev') + .$entrypointRenderer->renderLinks('theme-2', [], 'config2-dev'), + 'render correct global link attributes' + ); + } + + public function testMultipleConfigInDev() + { + $entrypointsLookupConfig1 = $this->getEntrypointsLookup('config1-dev'); + $entrypointsLookupConfig2 = $this->getEntrypointsLookup('config2-dev'); + + /** + * @var EntrypointsLookupCollection|Stub $entrypointsLookupCollection + */ + $entrypointsLookupCollection = $this->createStub(EntrypointsLookupCollection::class); + $entrypointsLookupCollection + ->method('getEntrypointsLookup') + ->will($this->returnValueMap([ + ['config1-dev', $entrypointsLookupConfig1], + ['config2-dev', $entrypointsLookupConfig2], + ])); + + $tagRendererConfig1 = new TagRenderer(); + $tagRendererConfig2 = new TagRenderer(); + + /** + * @var TagRendererCollection|Stub $tagRendererCollection + */ + $tagRendererCollection = $this->createStub(TagRendererCollection::class); + $tagRendererCollection + ->method('getTagRenderer') + ->will($this->returnValueMap([ + ['config1-dev', $tagRendererConfig1], + ['config2-dev', $tagRendererConfig2], + ])); + + $entrypointRenderer = new EntrypointRenderer( + $entrypointsLookupCollection, + $tagRendererCollection, + false, + null, + null, + ); + + $expectedScripts = '' + .'' + .'' + .''; + + $this->assertEquals( + $expectedScripts, + $entrypointRenderer->renderScripts('app-1', [], 'config1-dev') + .$entrypointRenderer->renderScripts('app-2', [], 'config2-dev'), + 'render multiple vite client' + ); + + $this->assertEquals( + '', + $entrypointRenderer->renderScripts('app-1', [], 'config1-dev') + .$entrypointRenderer->renderScripts('app-2', [], 'config2-dev'), + 'render multiple vite client' + ); + + $entrypointRenderer->reset(); + + $this->assertEquals( + $expectedScripts, + $entrypointRenderer->renderScripts('app-1', [], 'config1-dev') + .$entrypointRenderer->renderScripts('app-2', [], 'config2-dev'), + 'render multiple vite client' + ); + } +} diff --git a/tests/Asset/EntrypointsLookupTest.php b/tests/Asset/EntrypointsLookupTest.php index fbb003e..325b7dd 100644 --- a/tests/Asset/EntrypointsLookupTest.php +++ b/tests/Asset/EntrypointsLookupTest.php @@ -47,12 +47,12 @@ public function testViteServer() $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); $this->assertEquals( - ['origin' => 'http://127.0.0.1:5173', 'base' => '/build/'], + 'http://127.0.0.1:5173', $entrypointsLookupBasicDev->getViteServer() ); $this->assertEquals( - false, + null, $entrypointsLookupBasicBuild->getViteServer() ); @@ -90,14 +90,14 @@ public function devfilesProvider() /** * @dataProvider devfilesProvider */ - public function testGetDevFiles($entryName, $files) + public function testGetDevFiles($entryName, $expectedFiles) { $entrypointsLookupBasicDev = $this->getEntrypointsLookup('basic-dev'); - $this->assertEquals($files['css'], $entrypointsLookupBasicDev->getCSSFiles($entryName)); - $this->assertEquals($files['dynamic'], $entrypointsLookupBasicDev->getJavascriptDynamicDependencies($entryName)); - $this->assertEquals($files['js'], $entrypointsLookupBasicDev->getJSFiles($entryName)); - $this->assertEquals($files['preload'], $entrypointsLookupBasicDev->getJavascriptDependencies($entryName)); + $this->assertEquals($expectedFiles['css'], $entrypointsLookupBasicDev->getCSSFiles($entryName)); + $this->assertEquals($expectedFiles['dynamic'], $entrypointsLookupBasicDev->getJavascriptDynamicDependencies($entryName)); + $this->assertEquals($expectedFiles['js'], $entrypointsLookupBasicDev->getJSFiles($entryName)); + $this->assertEquals($expectedFiles['preload'], $entrypointsLookupBasicDev->getJavascriptDependencies($entryName)); } public function buildfilesProvider() @@ -107,29 +107,29 @@ public function buildfilesProvider() 'assets' => [], 'css' => [], 'dynamic' => [], - 'js' => ['/build/assets/pageImports-53eb9fd1.js'], + 'js' => ['/build/assets/app.js'], 'preload' => [], ]], ['theme', [ 'assets' => [], - 'css' => ['/build/assets/theme-62617963.css'], + 'css' => ['/build/assets/theme.css'], 'dynamic' => [], 'js' => [], 'preload' => [], ]], ['with-dep', [ 'assets' => [], - 'css' => ['/build/assets/main-76fa9059.css'], + 'css' => ['/build/assets/main.css'], 'dynamic' => [], - 'js' => ['/build/assets/main-e664f4b5.js'], - 'preload' => ['/build/assets/vue-2d05229a.js', '/build/assets/react-2d05228c.js'], + 'js' => ['/build/assets/main.js'], + 'preload' => ['/build/assets/vue.js', '/build/assets/react.js'], ]], ['with-async', [ 'assets' => [], - 'css' => ['/build/assets/main-76fa9059.css'], - 'dynamic' => ['/build/assets/async-script-12324565.js'], - 'js' => ['/build/assets/main-e664f4b5.js'], - 'preload' => ['/build/assets/vue-2d05229a.js', '/build/assets/react-2d05228c.js'], + 'css' => ['/build/assets/main.css'], + 'dynamic' => ['/build/assets/async-script.js'], + 'js' => ['/build/assets/main.js'], + 'preload' => ['/build/assets/vue.js', '/build/assets/react.js'], ]], ]; } @@ -137,14 +137,14 @@ public function buildfilesProvider() /** * @dataProvider buildfilesProvider */ - public function testGetBuildFiles($entryName, $files) + public function testGetBuildFiles($entryName, $expectedFiles) { $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); - $this->assertEquals($files['css'], $entrypointsLookupBasicBuild->getCSSFiles($entryName)); - $this->assertEquals($files['dynamic'], $entrypointsLookupBasicBuild->getJavascriptDynamicDependencies($entryName)); - $this->assertEquals($files['js'], $entrypointsLookupBasicBuild->getJSFiles($entryName)); - $this->assertEquals($files['preload'], $entrypointsLookupBasicBuild->getJavascriptDependencies($entryName)); + $this->assertEquals($expectedFiles['css'], $entrypointsLookupBasicBuild->getCSSFiles($entryName)); + $this->assertEquals($expectedFiles['dynamic'], $entrypointsLookupBasicBuild->getJavascriptDynamicDependencies($entryName)); + $this->assertEquals($expectedFiles['js'], $entrypointsLookupBasicBuild->getJSFiles($entryName)); + $this->assertEquals($expectedFiles['preload'], $entrypointsLookupBasicBuild->getJavascriptDependencies($entryName)); } public function buildLegacyProvider() @@ -154,17 +154,17 @@ public function buildLegacyProvider() 'assets' => [], 'css' => [], 'dynamic' => [], - 'js' => ['/build/assets/app-23802617.js'], + 'js' => ['/build/assets/app.js'], 'preload' => [], - 'legacy_js' => '/build/assets/app-legacy-59951366.js', + 'legacy_js' => '/build/assets/app-legacy.js', ]], ['theme', [ 'assets' => [], - 'css' => ['/build/assets/theme-5cd46aed.css'], + 'css' => ['/build/assets/theme.css'], 'dynamic' => [], 'js' => [], 'preload' => [], - 'legacy_js' => '/build/assets/theme-legacy-de9eb869.js', + 'legacy_js' => '/build/assets/theme-legacy.js', ]], ]; } @@ -172,15 +172,15 @@ public function buildLegacyProvider() /** * @dataProvider buildLegacyProvider */ - public function testGetBuildLegacyFiles($entryName, $files) + public function testGetBuildLegacyFiles($entryName, $expectedFiles) { $entrypointsLookupLegacyBuild = $this->getEntrypointsLookup('legacy-build'); - $this->assertEquals($files['css'], $entrypointsLookupLegacyBuild->getCSSFiles($entryName)); - $this->assertEquals($files['dynamic'], $entrypointsLookupLegacyBuild->getJavascriptDynamicDependencies($entryName)); - $this->assertEquals($files['js'], $entrypointsLookupLegacyBuild->getJSFiles($entryName)); - $this->assertEquals($files['preload'], $entrypointsLookupLegacyBuild->getJavascriptDependencies($entryName)); - $this->assertEquals($files['legacy_js'], $entrypointsLookupLegacyBuild->getLegacyJSFile($entryName)); + $this->assertEquals($expectedFiles['css'], $entrypointsLookupLegacyBuild->getCSSFiles($entryName)); + $this->assertEquals($expectedFiles['dynamic'], $entrypointsLookupLegacyBuild->getJavascriptDynamicDependencies($entryName)); + $this->assertEquals($expectedFiles['js'], $entrypointsLookupLegacyBuild->getJSFiles($entryName)); + $this->assertEquals($expectedFiles['preload'], $entrypointsLookupLegacyBuild->getJavascriptDependencies($entryName)); + $this->assertEquals($expectedFiles['legacy_js'], $entrypointsLookupLegacyBuild->getLegacyJSFile($entryName)); } public function testHashOfFiles() @@ -188,13 +188,13 @@ public function testHashOfFiles() $entrypointsLookupBasicBuild = $this->getEntrypointsLookup('basic-build'); $this->assertEquals( null, - $entrypointsLookupBasicBuild->getFileHash('/build/assets/pageImports-53eb9fd1.js') + $entrypointsLookupBasicBuild->getFileHash('/build/assets/app.js') ); $entrypointsLookupMetadataBuild = $this->getEntrypointsLookup('metadata-build'); $this->assertEquals( - 'sha256-qABtt8+MbhDq8dts7DSJOnBqCO1QbV2S6zg24ylLkKY=', - $entrypointsLookupMetadataBuild->getFileHash('http://cdn.with-cdn.symfony-vite-dev.localhost/assets/pageVue-bda8ac3b.js') + 'sha256-XYZ', + $entrypointsLookupMetadataBuild->getFileHash('/build/assets/app.js') ); $entrypointsLookupMetadataBuild = $this->getEntrypointsLookup('metadata-build'); diff --git a/tests/fixtures/entrypoints/basic-build/entrypoints.json b/tests/fixtures/entrypoints/basic-build/entrypoints.json index 799a1ef..b49838d 100644 --- a/tests/fixtures/entrypoints/basic-build/entrypoints.json +++ b/tests/fixtures/entrypoints/basic-build/entrypoints.json @@ -1,11 +1,12 @@ { + "base": "/build/", "entryPoints": { "app": { "assets": [], "css": [], "dynamic": [], "js": [ - "/build/assets/pageImports-53eb9fd1.js" + "/build/assets/app.js" ], "legacy": false, "preload": [] @@ -13,7 +14,7 @@ "theme": { "assets": [], "css": [ - "/build/assets/theme-62617963.css" + "/build/assets/theme.css" ], "dynamic": [], "js": [], @@ -23,37 +24,37 @@ "with-dep": { "assets": [], "css": [ - "/build/assets/main-76fa9059.css" + "/build/assets/main.css" ], "dynamic": [], "js": [ - "/build/assets/main-e664f4b5.js" + "/build/assets/main.js" ], "legacy": false, "preload": [ - "/build/assets/vue-2d05229a.js", - "/build/assets/react-2d05228c.js" + "/build/assets/vue.js", + "/build/assets/react.js" ] }, "with-async": { "assets": [], "css": [ - "/build/assets/main-76fa9059.css" + "/build/assets/main.css" ], "dynamic": [ - "/build/assets/async-script-12324565.js" + "/build/assets/async-script.js" ], "js": [ - "/build/assets/main-e664f4b5.js" + "/build/assets/main.js" ], "legacy": false, "preload": [ - "/build/assets/vue-2d05229a.js", - "/build/assets/react-2d05228c.js" + "/build/assets/vue.js", + "/build/assets/react.js" ] } }, "legacy": false, "metadatas": {}, - "viteServer": false + "viteServer": null } \ No newline at end of file diff --git a/tests/fixtures/entrypoints/basic-dev/entrypoints.json b/tests/fixtures/entrypoints/basic-dev/entrypoints.json index 9e27575..bcb98ab 100644 --- a/tests/fixtures/entrypoints/basic-dev/entrypoints.json +++ b/tests/fixtures/entrypoints/basic-dev/entrypoints.json @@ -1,4 +1,5 @@ { + "base": "/build/", "entryPoints": { "app": { "js": [ @@ -13,8 +14,5 @@ }, "legacy": false, "metadatas": {}, - "viteServer": { - "origin": "http://127.0.0.1:5173", - "base": "/build/" - } + "viteServer": "http://127.0.0.1:5173" } \ No newline at end of file diff --git a/tests/fixtures/entrypoints/config1-build/entrypoints.json b/tests/fixtures/entrypoints/config1-build/entrypoints.json new file mode 100644 index 0000000..b4e8737 --- /dev/null +++ b/tests/fixtures/entrypoints/config1-build/entrypoints.json @@ -0,0 +1,28 @@ +{ + "base": "/build-config1/", + "entryPoints": { + "app-1": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "/build-config1/assets/app-1.js" + ], + "legacy": false, + "preload": [] + }, + "theme-1": { + "assets": [], + "css": [ + "/build-config1/assets/theme-1.css" + ], + "dynamic": [], + "js": [], + "legacy": false, + "preload": [] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": null +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/config1-dev/entrypoints.json b/tests/fixtures/entrypoints/config1-dev/entrypoints.json new file mode 100644 index 0000000..f01c65b --- /dev/null +++ b/tests/fixtures/entrypoints/config1-dev/entrypoints.json @@ -0,0 +1,18 @@ +{ + "base": "/build-config1/", + "entryPoints": { + "app-1": { + "js": [ + "http://127.0.0.1:5173/build-config1/assets/app-1.js" + ] + }, + "theme-1": { + "css": [ + "http://127.0.0.1:5173/build-config1/assets/theme-1.scss" + ] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": "http://127.0.0.1:5173" +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/config2-build/entrypoints.json b/tests/fixtures/entrypoints/config2-build/entrypoints.json new file mode 100644 index 0000000..6720c31 --- /dev/null +++ b/tests/fixtures/entrypoints/config2-build/entrypoints.json @@ -0,0 +1,28 @@ +{ + "base": "/build/", + "entryPoints": { + "app-2": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "/build-config2/assets/app-2.js" + ], + "legacy": false, + "preload": [] + }, + "theme-2": { + "assets": [], + "css": [ + "/build-config2/assets/theme-2.css" + ], + "dynamic": [], + "js": [], + "legacy": false, + "preload": [] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": null +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/config2-dev/entrypoints.json b/tests/fixtures/entrypoints/config2-dev/entrypoints.json new file mode 100644 index 0000000..8c5317d --- /dev/null +++ b/tests/fixtures/entrypoints/config2-dev/entrypoints.json @@ -0,0 +1,18 @@ +{ + "base": "/build-config2/", + "entryPoints": { + "app-2": { + "js": [ + "http://127.0.0.1:5174/build-config2/assets/app-2.js" + ] + }, + "theme-2": { + "css": [ + "http://127.0.0.1:5174/build-config2/assets/theme-2.scss" + ] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": "http://127.0.0.1:5174" +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/duplication-build/entrypoints.json b/tests/fixtures/entrypoints/duplication-build/entrypoints.json new file mode 100644 index 0000000..e4990c8 --- /dev/null +++ b/tests/fixtures/entrypoints/duplication-build/entrypoints.json @@ -0,0 +1,34 @@ +{ + "base": "/build/", + "entryPoints": { + "app-1": { + "assets": [], + "css": [], + "dynamic": [], + "js": [ + "/build/assets/app-1.js" + ], + "legacy": false, + "preload": [ + "/build/assets/vue.js" + ] + }, + "app-2": { + "assets": [], + "css": [ + "/build/assets/app-2.css" + ], + "dynamic": [], + "js": [ + "/build/assets/app-2.js" + ], + "legacy": false, + "preload": [ + "/build/assets/vue.js" + ] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": null +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/duplication-dev/entrypoints.json b/tests/fixtures/entrypoints/duplication-dev/entrypoints.json new file mode 100644 index 0000000..799dc40 --- /dev/null +++ b/tests/fixtures/entrypoints/duplication-dev/entrypoints.json @@ -0,0 +1,23 @@ +{ + "base": "/build/", + "entryPoints": { + "app": { + "js": [ + "http://127.0.0.1:5173/build/assets/app.js" + ] + }, + "other-app": { + "js": [ + "http://127.0.0.1:5173/build/assets/other-app.js" + ] + }, + "theme": { + "css": [ + "http://127.0.0.1:5173/build/assets/theme.scss" + ] + } + }, + "legacy": false, + "metadatas": {}, + "viteServer": "http://127.0.0.1:5173" +} \ No newline at end of file diff --git a/tests/fixtures/entrypoints/legacy-build/entrypoints.json b/tests/fixtures/entrypoints/legacy-build/entrypoints.json index a9dcdb9..12c6d16 100644 --- a/tests/fixtures/entrypoints/legacy-build/entrypoints.json +++ b/tests/fixtures/entrypoints/legacy-build/entrypoints.json @@ -1,11 +1,12 @@ { + "base": "/build/", "entryPoints": { "app-legacy": { "assets": [], "css": [], "dynamic": [], "js": [ - "/build/assets/app-legacy-59951366.js" + "/build/assets/app-legacy.js" ], "legacy": false, "preload": [] @@ -15,19 +16,19 @@ "css": [], "dynamic": [], "js": [ - "/build/assets/app-23802617.js" + "/build/assets/app.js" ], "legacy": "app-legacy", "preload": [] }, "theme-legacy": { "assets": [ - "/build/assets/topography-303b8303.svg" + "/build/assets/topography-svg" ], "css": [], "dynamic": [], "js": [ - "/build/assets/theme-legacy-de9eb869.js" + "/build/assets/theme-legacy.js" ], "legacy": false, "preload": [] @@ -35,7 +36,7 @@ "theme": { "assets": [], "css": [ - "/build/assets/theme-5cd46aed.css" + "/build/assets/theme.css" ], "dynamic": [], "js": [], @@ -47,7 +48,7 @@ "css": [], "dynamic": [], "js": [ - "/build/assets/polyfills-legacy-40963d34.js" + "/build/assets/polyfills-legacy.js" ], "legacy": false, "preload": [] @@ -55,5 +56,5 @@ }, "legacy": true, "metadatas": {}, - "viteServer": false + "viteServer": null } \ No newline at end of file diff --git a/tests/fixtures/entrypoints/metadata-build/entrypoints.json b/tests/fixtures/entrypoints/metadata-build/entrypoints.json index d3aacf6..29853c0 100644 --- a/tests/fixtures/entrypoints/metadata-build/entrypoints.json +++ b/tests/fixtures/entrypoints/metadata-build/entrypoints.json @@ -1,11 +1,12 @@ { + "base": "/build/", "entryPoints": { - "pageVue": { + "app": { "assets": [], "css": [], "dynamic": [], "js": [ - "http://cdn.with-cdn.symfony-vite-dev.localhost/assets/pageVue-bda8ac3b.js" + "/build/assets/app.js" ], "legacy": false, "preload": [] @@ -13,9 +14,9 @@ }, "legacy": false, "metadatas": { - "http://cdn.with-cdn.symfony-vite-dev.localhost/assets/pageVue-bda8ac3b.js": { - "hash": "sha256-qABtt8+MbhDq8dts7DSJOnBqCO1QbV2S6zg24ylLkKY=" + "/build/assets/app.js": { + "hash": "sha256-XYZ" } }, - "viteServer": false + "viteServer": null } \ No newline at end of file From 816dcebdb68031741cb31867330dd7f63116fee9 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Tue, 31 Oct 2023 14:49:18 +0100 Subject: [PATCH 07/19] add preload option --- CHANGELOG.md | 2 + composer.json | 3 +- composer.lock | 211 +++++++++++++++--- src/Asset/EntrypointRenderer.php | 53 +++-- src/DependencyInjection/Configuration.php | 5 + .../PentatrionViteExtension.php | 14 +- .../PreloadAssetsEventListener.php | 65 ++++++ src/Resources/config/services.yaml | 8 + tests/Asset/EntrypointRendererTest.php | 76 ++++--- .../config2-build/entrypoints.json | 2 +- 10 files changed, 352 insertions(+), 87 deletions(-) create mode 100644 src/EventListener/PreloadAssetsEventListener.php diff --git a/CHANGELOG.md b/CHANGELOG.md index fc337e8..5c317e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## Next - make services privates. +- add tests for EntrypointRenderer, EntrypointsLookup and TagRenderer. +- add preload option (symfony/web-link) ## v5.0.1 diff --git a/composer.json b/composer.json index f2ee866..4104626 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,8 @@ "friendsofphp/php-cs-fixer": "^3.9", "phpstan/phpstan": "^1.8", "phpunit/phpunit": "^9.5", - "symfony/phpunit-bridge": "^4.4 || ^5.0 || ^6.0 || ^7.0" + "symfony/phpunit-bridge": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "symfony/web-link": "^4.4 || ^5.0 || ^6.0 || ^7.0" }, "scripts": { "cs-fix": "php8.1 vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php", diff --git a/composer.lock b/composer.lock index 6349663..e176f96 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": "0621f19a1a733ca72da436652082e9aa", + "content-hash": "10c9d61736ec57babdfdb4c006dcc26b", "packages": [ { "name": "psr/cache", @@ -1031,16 +1031,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "5b5dca452a70d06d0463d3aeae640b2d034ef485" + "reference": "dba20792c726c30d455626eddfb2db008f64085f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/5b5dca452a70d06d0463d3aeae640b2d034ef485", - "reference": "5b5dca452a70d06d0463d3aeae640b2d034ef485", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/dba20792c726c30d455626eddfb2db008f64085f", + "reference": "dba20792c726c30d455626eddfb2db008f64085f", "shasum": "" }, "require": { @@ -1155,7 +1155,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.3.6" + "source": "https://github.com/symfony/framework-bundle/tree/v6.3.7" }, "funding": [ { @@ -1171,20 +1171,20 @@ "type": "tidelift" } ], - "time": "2023-10-12T17:41:20+00:00" + "time": "2023-10-26T18:15:14+00:00" }, { "name": "symfony/http-client", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "ab8446f997efb9913627e9da10fa784d2182fe92" + "reference": "cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/ab8446f997efb9913627e9da10fa784d2182fe92", - "reference": "ab8446f997efb9913627e9da10fa784d2182fe92", + "url": "https://api.github.com/repos/symfony/http-client/zipball/cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d", + "reference": "cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d", "shasum": "" }, "require": { @@ -1247,7 +1247,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.3.6" + "source": "https://github.com/symfony/http-client/tree/v6.3.7" }, "funding": [ { @@ -1263,7 +1263,7 @@ "type": "tidelift" } ], - "time": "2023-10-06T10:08:56+00:00" + "time": "2023-10-29T12:41:36+00:00" }, { "name": "symfony/http-client-contracts", @@ -1345,16 +1345,16 @@ }, { "name": "symfony/http-foundation", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "c186627f52febe09c6d5270b04f8462687a250a6" + "reference": "59d1837d5d992d16c2628cd0d6b76acf8d69b33e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c186627f52febe09c6d5270b04f8462687a250a6", - "reference": "c186627f52febe09c6d5270b04f8462687a250a6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/59d1837d5d992d16c2628cd0d6b76acf8d69b33e", + "reference": "59d1837d5d992d16c2628cd0d6b76acf8d69b33e", "shasum": "" }, "require": { @@ -1402,7 +1402,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.3.6" + "source": "https://github.com/symfony/http-foundation/tree/v6.3.7" }, "funding": [ { @@ -1418,20 +1418,20 @@ "type": "tidelift" } ], - "time": "2023-10-17T11:32:53+00:00" + "time": "2023-10-28T23:55:27+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "4945f5001b06ff9080cd3d8f1f9f069094c0d156" + "reference": "6d4098095f93279d9536a0e9124439560cc764d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4945f5001b06ff9080cd3d8f1f9f069094c0d156", - "reference": "4945f5001b06ff9080cd3d8f1f9f069094c0d156", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6d4098095f93279d9536a0e9124439560cc764d0", + "reference": "6d4098095f93279d9536a0e9124439560cc764d0", "shasum": "" }, "require": { @@ -1515,7 +1515,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.3.6" + "source": "https://github.com/symfony/http-kernel/tree/v6.3.7" }, "funding": [ { @@ -1531,7 +1531,7 @@ "type": "tidelift" } ], - "time": "2023-10-21T13:12:51+00:00" + "time": "2023-10-29T14:31:45+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2818,16 +2818,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.35.1", + "version": "v3.37.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "ec1ccc264994b6764882669973ca435cf05bab08" + "reference": "c3fe76976081ab871aa654e872da588077e19679" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ec1ccc264994b6764882669973ca435cf05bab08", - "reference": "ec1ccc264994b6764882669973ca435cf05bab08", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/c3fe76976081ab871aa654e872da588077e19679", + "reference": "c3fe76976081ab871aa654e872da588077e19679", "shasum": "" }, "require": { @@ -2899,7 +2899,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.35.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.37.1" }, "funding": [ { @@ -2907,7 +2907,7 @@ "type": "github" } ], - "time": "2023-10-12T13:47:26+00:00" + "time": "2023-10-29T20:51:23+00:00" }, { "name": "myclabs/deep-copy", @@ -3137,16 +3137,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.39", + "version": "1.10.40", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4" + "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d9dedb0413f678b4d03cbc2279a48f91592c97c4", - "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/93c84b5bf7669920d823631e39904d69b9c7dc5d", + "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d", "shasum": "" }, "require": { @@ -3195,7 +3195,7 @@ "type": "tidelift" } ], - "time": "2023-10-17T15:46:26+00:00" + "time": "2023-10-30T14:48:31+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3619,6 +3619,62 @@ ], "time": "2023-09-19T05:39:22+00:00" }, + { + "name": "psr/link", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/link.git", + "reference": "84b159194ecfd7eaa472280213976e96415433f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/link/zipball/84b159194ecfd7eaa472280213976e96415433f7", + "reference": "84b159194ecfd7eaa472280213976e96415433f7", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "suggest": { + "fig/link-util": "Provides some useful PSR-13 utilities" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Link\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for HTTP links", + "homepage": "https://github.com/php-fig/link", + "keywords": [ + "http", + "http-link", + "link", + "psr", + "psr-13", + "rest" + ], + "support": { + "source": "https://github.com/php-fig/link/tree/2.0.1" + }, + "time": "2021-03-11T23:00:27+00:00" + }, { "name": "sebastian/cli-parser", "version": "1.0.1", @@ -5274,6 +5330,89 @@ ], "time": "2023-09-18T10:38:32+00:00" }, + { + "name": "symfony/web-link", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/web-link.git", + "reference": "0989ca617d0703cdca501a245f10e194ff22315b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/web-link/zipball/0989ca617d0703cdca501a245f10e194ff22315b", + "reference": "0989ca617d0703cdca501a245f10e194ff22315b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/link": "^1.1|^2.0" + }, + "conflict": { + "symfony/http-kernel": "<5.4" + }, + "provide": { + "psr/link-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/http-kernel": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\WebLink\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Manages links between resources", + "homepage": "https://symfony.com", + "keywords": [ + "dns-prefetch", + "http", + "http2", + "link", + "performance", + "prefetch", + "preload", + "prerender", + "psr13", + "push" + ], + "support": { + "source": "https://github.com/symfony/web-link/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-04-21T14:41:17+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.1", diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index 968fd23..b3d78b0 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -11,6 +11,7 @@ class EntrypointRenderer private EntrypointsLookupCollection $entrypointsLookupCollection; private TagRendererCollection $tagRendererCollection; private bool $useAbsoluteUrl; + private string $preload; private ?RouterInterface $router; private ?EventDispatcherInterface $eventDispatcher; @@ -18,18 +19,23 @@ class EntrypointRenderer private $returnedReactRefresh = []; private $returnedViteLegacyScripts = []; - private $renderedFiles = []; + private $renderedFiles = [ + 'scripts' => [], + 'styles' => [], + ]; public function __construct( EntrypointsLookupCollection $entrypointsLookupCollection, TagRendererCollection $tagRendererCollection, - bool $useAbsoluteUrl, + bool $useAbsoluteUrl = false, + string $preload = 'link-tag', RouterInterface $router = null, EventDispatcherInterface $eventDispatcher = null ) { $this->entrypointsLookupCollection = $entrypointsLookupCollection; $this->tagRendererCollection = $tagRendererCollection; $this->useAbsoluteUrl = $useAbsoluteUrl; + $this->preload = $preload; $this->router = $router; $this->eventDispatcher = $eventDispatcher; } @@ -71,12 +77,25 @@ public function getMode(string $configName = null): ?string return $entrypointsLookup->isBuild() ? 'build' : 'dev'; } - public function reset() + public function reset(): void { $this->returnedViteClients = []; $this->returnedReactRefresh = []; $this->returnedViteLegacyScripts = []; - $this->renderedFiles = []; + $this->renderedFiles = [ + 'scripts' => [], + 'styles' => [], + ]; + } + + public function getRenderedScripts(): array + { + return $this->renderedFiles['scripts']; + } + + public function getRenderedStyles(): array + { + return $this->renderedFiles['styles']; } public function renderScripts( @@ -141,7 +160,7 @@ public function renderScripts( /* normal js scripts */ foreach ($entrypointsLookup->getJSFiles($entryName) as $filePath) { - if (false === \in_array($filePath, $this->renderedFiles, true)) { + if (false === \in_array($filePath, $this->renderedFiles['scripts'], true)) { $tags[] = $tagRenderer->createScriptTag( array_merge( [ @@ -153,7 +172,7 @@ public function renderScripts( ) ); - $this->renderedFiles[] = $filePath; + $this->renderedFiles['scripts'][] = $filePath; } } @@ -162,7 +181,7 @@ public function renderScripts( $id = self::pascalToKebab("vite-legacy-entry-$entryName"); $filePath = $entrypointsLookup->getLegacyJSFile($entryName); - if (false === \in_array($filePath, $this->renderedFiles, true)) { + if (false === \in_array($filePath, $this->renderedFiles['scripts'], true)) { $tags[] = $tagRenderer->createScriptTag( [ 'nomodule' => true, @@ -175,7 +194,7 @@ public function renderScripts( InlineContent::getSystemJSInlineCode($id) ); - $this->renderedFiles[] = $filePath; + $this->renderedFiles['scripts'][] = $filePath; } } @@ -201,35 +220,35 @@ public function renderLinks( $tags = []; foreach ($entrypointsLookup->getCSSFiles($entryName) as $filePath) { - if (false === \in_array($filePath, $this->renderedFiles, true)) { + if (false === \in_array($filePath, $this->renderedFiles['styles'], true)) { $tags[] = $tagRenderer->createLinkStylesheetTag( $this->completeURL($filePath, $useAbsoluteUrl), array_merge(['integrity' => $entrypointsLookup->getFileHash($filePath)], $options['attr'] ?? []) ); - $this->renderedFiles[] = $filePath; + $this->renderedFiles['styles'][] = $filePath; } } if ($isBuild) { foreach ($entrypointsLookup->getJavascriptDependencies($entryName) as $filePath) { - if (false === \in_array($filePath, $this->renderedFiles, true)) { + if (false === \in_array($filePath, $this->renderedFiles['scripts'], true)) { $tags[] = $tagRenderer->createModulePreloadLinkTag( $this->completeURL($filePath, $useAbsoluteUrl), ['integrity' => $entrypointsLookup->getFileHash($filePath)] ); - $this->renderedFiles[] = $filePath; + $this->renderedFiles['scripts'][] = $filePath; } } } if ($isBuild && isset($options['preloadDynamicImports']) && true === $options['preloadDynamicImports']) { foreach ($entrypointsLookup->getJavascriptDynamicDependencies($entryName) as $filePath) { - if (false === \in_array($filePath, $this->renderedFiles, true)) { + if (false === \in_array($filePath, $this->renderedFiles['scripts'], true)) { $tags[] = $tagRenderer->createModulePreloadLinkTag( $this->completeURL($filePath, $useAbsoluteUrl), ['integrity' => $entrypointsLookup->getFileHash($filePath)] ); - $this->renderedFiles[] = $filePath; + $this->renderedFiles['scripts'][] = $filePath; } } } @@ -245,6 +264,12 @@ public function renderTags(array $tags, $isBuild, $toString) } } + if ('link-tag' !== $this->preload) { + $tags = array_filter($tags, function (Tag $tag) { + return !$tag->isModulePreload(); + }); + } + return $toString ? implode('', array_map(function ($tagEvent) { return TagRenderer::generateTag($tagEvent); diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 8ebec11..0640a4b 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -35,6 +35,11 @@ public function getConfigTreeBuilder(): TreeBuilder ->info('Prepend the rendered link and script tags with an absolute URL.') ->defaultValue(false) ->end() + ->enumNode('preload') + ->values(['none', 'link-tag', 'link-header']) + ->info('preload all rendered script and link tags automatically via the http2 Link header. (symfony/web-link is required) Instead will be used.') + ->defaultValue('link-tag') + ->end() ->arrayNode('script_attributes') ->info('Key/value pair of attributes to render on all script tags') ->example('{ defer: true, referrerpolicy: "origin" }') diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index 6405185..e86d9a7 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -11,6 +11,7 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\WebLink\EventListener\AddLinkHeaderListener; class PentatrionViteExtension extends Extension { @@ -58,6 +59,15 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void ]; } + if ('link-header' === $bundleConfig['preload']) { + if (!class_exists(AddLinkHeaderListener::class)) { + throw new \LogicException('To use the "preload" option, the WebLink component must be installed. Try running "composer require symfony/web-link".'); + } + } else { + $container->removeDefinition('pentatrion_vite.preload_assets_event_listener'); + } + $container->setParameter('pentatrion_vite.preload', $bundleConfig['preload']); + $container->setParameter('pentatrion_vite.public_directory', self::preparePublicDirectory($bundleConfig['public_directory'])); $container->setParameter('pentatrion_vite.default_config', $defaultConfigName); $container->setParameter('pentatrion_vite.configs', $configs); @@ -73,10 +83,6 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $container->getDefinition('pentatrion_vite.tag_renderer_collection') ->addArgument(ServiceLocatorTagPass::register($container, $tagRendererFactories)) ->addArgument($defaultConfigName); - - // $container->getDefinition('pentatrion_vite.tag_renderer') - // ->replaceArgument(0, $defaultConfigName) - // ->replaceArgument(1, $configs); } private function entrypointsLookupFactory( diff --git a/src/EventListener/PreloadAssetsEventListener.php b/src/EventListener/PreloadAssetsEventListener.php new file mode 100644 index 0000000..729a18b --- /dev/null +++ b/src/EventListener/PreloadAssetsEventListener.php @@ -0,0 +1,65 @@ +entrypointRenderer = $entrypointRenderer; + } + + public function onKernelResponse(ResponseEvent $event): void + { + if (!$event->isMainRequest()) { + return; + } + + $request = $event->getRequest(); + + if (null === $linkProvider = $request->attributes->get('_links')) { + $request->attributes->set( + '_links', + new GenericLinkProvider() + ); + } + + /** @var GenericLinkProvider $linkProvider */ + $linkProvider = $request->attributes->get('_links'); + + foreach ($this->entrypointRenderer->getRenderedScripts() as $href) { + $link = $this->createLink('preload', $href)->withAttribute('as', 'script'); + + $linkProvider = $linkProvider->withLink($link); + } + + foreach ($this->entrypointRenderer->getRenderedStyles() as $href) { + $link = $this->createLink('preload', $href)->withAttribute('as', 'style'); + + $linkProvider = $linkProvider->withLink($link); + } + + $request->attributes->set('_links', $linkProvider); + } + + private function createLink(string $rel, string $href): Link + { + return new Link($rel, $href); + } + + public static function getSubscribedEvents() + { + return [ + // must run before AddLinkHeaderListener + 'kernel.response' => ['onKernelResponse', 50], + ]; + } +} diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index d04f74f..d646c60 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -23,6 +23,7 @@ services: - "@pentatrion_vite.entrypoints_lookup_collection" - "@pentatrion_vite.tag_renderer_collection" - "%pentatrion_vite.absolute_url%" + - "%pentatrion_vite.preload%" - "@?router" - "@?event_dispatcher" @@ -69,3 +70,10 @@ services: - "%pentatrion_vite.absolute_url%" - "@?router" - true + + pentatrion_vite.preload_assets_event_listener: + class: Pentatrion\ViteBundle\EventListener\PreloadAssetsEventListener + tags: ["kernel.event_subscriber"] + arguments: + - "@pentatrion_vite.entrypoint_renderer" + diff --git a/tests/Asset/EntrypointRendererTest.php b/tests/Asset/EntrypointRendererTest.php index fff2520..c712c79 100644 --- a/tests/Asset/EntrypointRendererTest.php +++ b/tests/Asset/EntrypointRendererTest.php @@ -210,10 +210,7 @@ public function testBasic($config, $entryName, $expectedStrings) $entrypointRenderer = new EntrypointRenderer( $this->getEntrypointsLookupCollection($entrypointsLookup), - $this->getBasicTagRendererCollection(), - false, - null, - null, + $this->getBasicTagRendererCollection() ); $this->assertEquals( @@ -237,10 +234,7 @@ public function testRenderOnlyOneViteClient() $entrypointsLookup = $this->getEntrypointsLookup('duplication-dev'); $entrypointRenderer = new EntrypointRenderer( $this->getEntrypointsLookupCollection($entrypointsLookup), - $this->getBasicTagRendererCollection(), - false, - null, - null, + $this->getBasicTagRendererCollection() ); $this->assertEquals( @@ -256,10 +250,7 @@ public function testRenderOnlyOneReactRefresh() $entrypointsLookup = $this->getEntrypointsLookup('duplication-dev'); $entrypointRenderer = new EntrypointRenderer( $this->getEntrypointsLookupCollection($entrypointsLookup), - $this->getBasicTagRendererCollection(), - false, - null, - null, + $this->getBasicTagRendererCollection() ); $this->assertEquals( @@ -276,10 +267,7 @@ public function testRenderOnlyOneFile() $entrypointsLookup = $this->getEntrypointsLookup('duplication-build'); $entrypointRenderer = new EntrypointRenderer( $this->getEntrypointsLookupCollection($entrypointsLookup), - $this->getBasicTagRendererCollection(), - false, - null, - null, + $this->getBasicTagRendererCollection() ); $expectedScripts = '' @@ -327,10 +315,7 @@ public function testRenderOnlyOneLegacyInlineContent() $entrypointsLookup = $this->getEntrypointsLookup('legacy-build'); $entrypointRenderer = new EntrypointRenderer( $this->getEntrypointsLookupCollection($entrypointsLookup), - $this->getBasicTagRendererCollection(), - false, - null, - null, + $this->getBasicTagRendererCollection() ); $this->assertEquals( @@ -378,6 +363,7 @@ public function testRenderWithAbsoluteUrl() $this->getEntrypointsLookupCollection($entrypointsLookupBasicBuild), $this->getBasicTagRendererCollection(), true, + 'link-tag', $router, null, ); @@ -391,6 +377,7 @@ public function testRenderWithAbsoluteUrl() $this->getEntrypointsLookupCollection($entrypointsLookupBasicBuild), $this->getBasicTagRendererCollection(), false, + 'link-tag', $router, null, ); @@ -404,6 +391,7 @@ public function testRenderWithAbsoluteUrl() $this->getEntrypointsLookupCollection($entrypointsLookupBasicDev), $this->getBasicTagRendererCollection(), true, + 'link-tag', $router, null, ); @@ -415,15 +403,46 @@ public function testRenderWithAbsoluteUrl() ); } - public function testRenderAndPreloadDynamicImports() + public function testRenderWithoutPreload() { $entrypointsLookup = $this->getEntrypointsLookup('basic-build'); $entrypointRenderer = new EntrypointRenderer( $this->getEntrypointsLookupCollection($entrypointsLookup), $this->getBasicTagRendererCollection(), false, - null, - null, + 'none' + ); + + $this->assertEquals( + '', + $entrypointRenderer->renderLinks('with-async', [ + 'preloadDynamicImports' => true, + ]), + 'render only css files' + ); + + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection(), + false, + 'link-header' + ); + + $this->assertEquals( + '', + $entrypointRenderer->renderLinks('with-async', [ + 'preloadDynamicImports' => true, + ]), + 'render only css files' + ); + } + + public function testRenderAndPreloadDynamicImports() + { + $entrypointsLookup = $this->getEntrypointsLookup('basic-build'); + $entrypointRenderer = new EntrypointRenderer( + $this->getEntrypointsLookupCollection($entrypointsLookup), + $this->getBasicTagRendererCollection() ); $this->assertEquals( @@ -472,6 +491,7 @@ public function testRenderWithEvent() $this->getEntrypointsLookupCollection($entrypointsLookup), $this->getBasicTagRendererCollection(['defer' => true], ['referrerpolicy' => 'origin']), false, + 'link-tag', null, $dispatcher, ); @@ -527,10 +547,7 @@ public function testMultipleConfigInBuild() $entrypointRenderer = new EntrypointRenderer( $entrypointsLookupCollection, - $tagRendererCollection, - false, - null, - null, + $tagRendererCollection ); $this->assertEquals( @@ -582,10 +599,7 @@ public function testMultipleConfigInDev() $entrypointRenderer = new EntrypointRenderer( $entrypointsLookupCollection, - $tagRendererCollection, - false, - null, - null, + $tagRendererCollection ); $expectedScripts = '' diff --git a/tests/fixtures/entrypoints/config2-build/entrypoints.json b/tests/fixtures/entrypoints/config2-build/entrypoints.json index 6720c31..18bec33 100644 --- a/tests/fixtures/entrypoints/config2-build/entrypoints.json +++ b/tests/fixtures/entrypoints/config2-build/entrypoints.json @@ -1,5 +1,5 @@ { - "base": "/build/", + "base": "/build-config2/", "entryPoints": { "app-2": { "assets": [], From de63d459ca07c6ea5071a27f1ad1fa4bfd5db6b4 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Tue, 31 Oct 2023 18:02:19 +0100 Subject: [PATCH 08/19] cache option implementation for entrypoints.json --- src/Asset/EntrypointsLookup.php | 31 +++++++++-- src/CacheWarmer/EntrypointsCacheWarmer.php | 42 +++++++++++++++ src/DependencyInjection/Configuration.php | 4 ++ .../PentatrionViteExtension.php | 51 +++++++++++++++---- .../EntrypointsFileNotFoundException.php | 7 +++ src/Resources/config/services.yaml | 17 +++++++ tests/Asset/EntrypointRendererTest.php | 50 +----------------- tests/Asset/EntrypointsLookupTest.php | 3 +- 8 files changed, 139 insertions(+), 66 deletions(-) create mode 100644 src/CacheWarmer/EntrypointsCacheWarmer.php create mode 100644 src/Exception/EntrypointsFileNotFoundException.php diff --git a/src/Asset/EntrypointsLookup.php b/src/Asset/EntrypointsLookup.php index 174295f..aba1958 100644 --- a/src/Asset/EntrypointsLookup.php +++ b/src/Asset/EntrypointsLookup.php @@ -3,16 +3,27 @@ namespace Pentatrion\ViteBundle\Asset; use Pentatrion\ViteBundle\Exception\EntrypointNotFoundException; +use Pentatrion\ViteBundle\Exception\EntrypointsFileNotFoundException; +use Psr\Cache\CacheItemPoolInterface; class EntrypointsLookup { + private string $configName; private bool $throwOnMissingEntry; + private ?CacheItemPoolInterface $cache; + private array $fileInfos; - public function __construct(string $publicPath, array $config, bool $throwOnMissingEntry) - { + public function __construct( + string $basePath, + string $configName = '_default', + bool $throwOnMissingEntry = false, + CacheItemPoolInterface $cache = null + ) { + $this->configName = $configName; $this->throwOnMissingEntry = $throwOnMissingEntry; - $entrypointsPath = $publicPath.$config['base'].'entrypoints.json'; + $this->cache = $cache; + $entrypointsPath = $basePath.'entrypoints.json'; $this->fileInfos = [ 'entrypointsPath' => $entrypointsPath, @@ -32,9 +43,17 @@ public function hasFile(): bool private function getFileContent(): array { + if ($this->cache) { + $cached = $this->cache->getItem($this->configName); + + if ($cached->isHit()) { + $this->fileInfos['content'] = $cached->get(); + } + } + if (!isset($this->fileInfos['content'])) { if (!$this->fileInfos['fileExists']) { - throw new \Exception('entrypoints.json not found at '.$this->fileInfos['entrypointsPath']); + throw new EntrypointsFileNotFoundException('entrypoints.json not found at '.$this->fileInfos['entrypointsPath']); } $content = json_decode(file_get_contents($this->fileInfos['entrypointsPath']), true); if (!array_key_exists('entryPoints', $content) @@ -44,6 +63,10 @@ private function getFileContent(): array throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints, base or viteServer not exists'); } + if (isset($cached)) { + $this->cache->save($cached->set($content)); + } + $this->fileInfos['content'] = $content; } diff --git a/src/CacheWarmer/EntrypointsCacheWarmer.php b/src/CacheWarmer/EntrypointsCacheWarmer.php new file mode 100644 index 0000000..ebf24fb --- /dev/null +++ b/src/CacheWarmer/EntrypointsCacheWarmer.php @@ -0,0 +1,42 @@ +basePaths = $basePaths; + parent::__construct($phpCacheFile); + } + + protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter): bool + { + foreach ($this->basePaths as $basePath) { + $entrypointsPath = $basePath.'entrypoints.json'; + + if (!file_exists($entrypointsPath)) { + continue; + } + + $entrypointsLookup = new EntrypointsLookup($entrypointsPath); + try { + // any method that will call getFileContent and generate + // the file in cache. + $entrypointsLookup->getBase(); + } catch (EntrypointsFileNotFoundException $e) { + // ignore exception + } + } + + return true; + } +} diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 0640a4b..9725d91 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -35,6 +35,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->info('Prepend the rendered link and script tags with an absolute URL.') ->defaultValue(false) ->end() + ->booleanNode('cache') + ->info('Enable caching of the entry point file(s)') + ->defaultFalse() + ->end() ->enumNode('preload') ->values(['none', 'link-tag', 'link-header']) ->info('preload all rendered script and link tags automatically via the http2 Link header. (symfony/web-link is required) Instead will be used.') diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index e86d9a7..9383e5b 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -32,6 +32,12 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $bundleConfig['default_config'] = $bundleConfig['default_build']; } + $container->setParameter('pentatrion_vite.preload', $bundleConfig['preload']); + $container->setParameter('pentatrion_vite.public_directory', self::preparePublicDirectory($bundleConfig['public_directory'])); + $container->setParameter('pentatrion_vite.absolute_url', $bundleConfig['absolute_url']); + $container->setParameter('pentatrion_vite.proxy_origin', $bundleConfig['proxy_origin']); + $container->setParameter('pentatrion_vite.throw_on_missing_entry', $bundleConfig['throw_on_missing_entry']); + if ( count($bundleConfig['configs']) > 0) { if (is_null($bundleConfig['default_config']) || !isset($bundleConfig['configs'][$bundleConfig['default_config']])) { @@ -41,22 +47,35 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $lookupFactories = []; $tagRendererFactories = []; $configs = []; + $cacheKeys = []; foreach ($bundleConfig['configs'] as $configName => $config) { $configs[$configName] = $configPrepared = self::prepareConfig($config); - $lookupFactories[$configName] = $this->entrypointsLookupFactory($container, $configName, $configPrepared); + $lookupFactories[$configName] = $this->entrypointsLookupFactory( + $container, + $configName, + $configPrepared, + $bundleConfig['cache'] + ); $tagRendererFactories[$configName] = $this->tagRendererFactory($container, $configName, $configPrepared); + $cacheKeys[] = $this->resolveBasePath($container, $configPrepared); } } else { $defaultConfigName = '_default'; $configs[$defaultConfigName] = $configPrepared = self::prepareConfig($bundleConfig); $lookupFactories = [ - '_default' => $this->entrypointsLookupFactory($container, $defaultConfigName, $configPrepared), + '_default' => $this->entrypointsLookupFactory( + $container, + $defaultConfigName, + $configPrepared, + $bundleConfig['cache'] + ), ]; $tagRendererFactories = [ '_default' => $this->tagRendererFactory($container, $defaultConfigName, $configPrepared), ]; + $cacheKeys = [$this->resolveBasePath($container, $configPrepared)]; } if ('link-header' === $bundleConfig['preload']) { @@ -66,16 +85,10 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void } else { $container->removeDefinition('pentatrion_vite.preload_assets_event_listener'); } - $container->setParameter('pentatrion_vite.preload', $bundleConfig['preload']); - $container->setParameter('pentatrion_vite.public_directory', self::preparePublicDirectory($bundleConfig['public_directory'])); $container->setParameter('pentatrion_vite.default_config', $defaultConfigName); $container->setParameter('pentatrion_vite.configs', $configs); - $container->setParameter('pentatrion_vite.absolute_url', $bundleConfig['absolute_url']); - $container->setParameter('pentatrion_vite.proxy_origin', $bundleConfig['proxy_origin']); - $container->setParameter('pentatrion_vite.throw_on_missing_entry', $bundleConfig['throw_on_missing_entry']); - $container->getDefinition('pentatrion_vite.entrypoints_lookup_collection') ->addArgument(ServiceLocatorTagPass::register($container, $lookupFactories)) ->addArgument($defaultConfigName); @@ -83,18 +96,23 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $container->getDefinition('pentatrion_vite.tag_renderer_collection') ->addArgument(ServiceLocatorTagPass::register($container, $tagRendererFactories)) ->addArgument($defaultConfigName); + + $container->getDefinition('pentatrion_vite.cache_warmer') + ->replaceArgument(0, $cacheKeys); } private function entrypointsLookupFactory( ContainerBuilder $container, string $configName, - array $config + array $config, + bool $cacheEnabled ): Reference { $id = $this->getServiceId('entrypoints_lookup', $configName); $arguments = [ - '%kernel.project_dir%%pentatrion_vite.public_directory%', - $config, + $this->resolveBasePath($container, $config), + $configName, '%pentatrion_vite.throw_on_missing_entry%', + $cacheEnabled ? new Reference('pentatrion_vite.cache') : null, ]; $definition = new Definition(EntrypointsLookup::class, $arguments); $container->setDefinition($id, $definition); @@ -102,6 +120,17 @@ private function entrypointsLookupFactory( return new Reference($id); } + /** + * Return absolute path to the build directory with final slash + * ex: "/path-to-your-project/public/build/". + */ + private function resolveBasePath(ContainerBuilder $container, $config): string + { + return $container->getParameter('kernel.project_dir') + .$container->getParameter('pentatrion_vite.public_directory') + .$config['base']; + } + private function tagRendererFactory( ContainerBuilder $container, string $configName, diff --git a/src/Exception/EntrypointsFileNotFoundException.php b/src/Exception/EntrypointsFileNotFoundException.php new file mode 100644 index 0000000..e7598d9 --- /dev/null +++ b/src/Exception/EntrypointsFileNotFoundException.php @@ -0,0 +1,7 @@ +createStub(EntrypointsLookup::class); - - // $entrypointsLookup - // ->method('hasFile') - // ->willReturn(true); - - // $entrypointsLookup - // ->method('isBuild') - // ->willReturn(false); - - // $entrypointsLookup - // ->method('getViteServer') - // ->willReturn([ - // 'origin' => 'http://127.0.0.1:5173', - // 'base' => '/build/', - // ]); - - // return $entrypointsLookup; - // } - - // public function getBaseBuildEntrypointsLookupStub() - // { - // /** - // * @var EntrypointsLookup|Stub $entrypointsLookup - // */ - // $entrypointsLookup = $this->createStub(EntrypointsLookup::class); - - // $entrypointsLookup - // ->method('hasFile') - // ->willReturn(true); - - // $entrypointsLookup - // ->method('isBuild') - // ->willReturn(true); - - // $entrypointsLookup - // ->method('getViteServer') - // ->willReturn(false); - - // return $entrypointsLookup; - // } - private function getEntrypointsLookup($prefix) { return new EntrypointsLookup( - __DIR__.'/../fixtures/entrypoints', - ['base' => '/'.$prefix.'/'], + __DIR__.'/../fixtures/entrypoints/'.$prefix.'/', true ); } diff --git a/tests/Asset/EntrypointsLookupTest.php b/tests/Asset/EntrypointsLookupTest.php index 325b7dd..451d744 100644 --- a/tests/Asset/EntrypointsLookupTest.php +++ b/tests/Asset/EntrypointsLookupTest.php @@ -11,8 +11,7 @@ class EntrypointsLookupTest extends TestCase private function getEntrypointsLookup($prefix) { return new EntrypointsLookup( - __DIR__.'/../fixtures/entrypoints', - ['base' => '/'.$prefix.'/'], + __DIR__.'/../fixtures/entrypoints/'.$prefix.'/', true ); } From bdb710e746ffad49722662b752b4b30dec2cd3a7 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Thu, 2 Nov 2023 12:03:18 +0100 Subject: [PATCH 09/19] cache implementation for manifest.json --- MiGRATION.md | 5 ++ src/Asset/EntrypointsLookup.php | 12 +-- src/Asset/ViteAssetVersionStrategy.php | 85 +++++++++++++------ src/CacheWarmer/EntrypointsCacheWarmer.php | 33 +++++-- .../PentatrionViteExtension.php | 10 +-- src/Resources/config/services.yaml | 20 +++-- tests/Asset/EntrypointRendererTest.php | 1 + tests/Asset/EntrypointsLookupTest.php | 1 + 8 files changed, 110 insertions(+), 57 deletions(-) create mode 100644 MiGRATION.md diff --git a/MiGRATION.md b/MiGRATION.md new file mode 100644 index 0000000..bc4815a --- /dev/null +++ b/MiGRATION.md @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/src/Asset/EntrypointsLookup.php b/src/Asset/EntrypointsLookup.php index aba1958..f52bede 100644 --- a/src/Asset/EntrypointsLookup.php +++ b/src/Asset/EntrypointsLookup.php @@ -16,7 +16,7 @@ class EntrypointsLookup public function __construct( string $basePath, - string $configName = '_default', + ?string $configName, // for cache to retrieve content : configName is cache key bool $throwOnMissingEntry = false, CacheItemPoolInterface $cache = null ) { @@ -44,10 +44,10 @@ public function hasFile(): bool private function getFileContent(): array { if ($this->cache) { - $cached = $this->cache->getItem($this->configName); + $entrypointsCacheItem = $this->cache->getItem("{$this->configName}.entrypoints"); - if ($cached->isHit()) { - $this->fileInfos['content'] = $cached->get(); + if ($entrypointsCacheItem->isHit()) { + $this->fileInfos['content'] = $entrypointsCacheItem->get(); } } @@ -63,8 +63,8 @@ private function getFileContent(): array throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints, base or viteServer not exists'); } - if (isset($cached)) { - $this->cache->save($cached->set($content)); + if (isset($entrypointsCacheItem)) { + $this->cache->save($entrypointsCacheItem->set($content)); } $this->fileInfos['content'] = $content; diff --git a/src/Asset/ViteAssetVersionStrategy.php b/src/Asset/ViteAssetVersionStrategy.php index 8815268..55445af 100644 --- a/src/Asset/ViteAssetVersionStrategy.php +++ b/src/Asset/ViteAssetVersionStrategy.php @@ -2,6 +2,7 @@ namespace Pentatrion\ViteBundle\Asset; +use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Asset\Exception\AssetNotFoundException; use Symfony\Component\Asset\Exception\RuntimeException; use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; @@ -11,44 +12,46 @@ class ViteAssetVersionStrategy implements VersionStrategyInterface { private string $publicPath; private array $configs; + private string $configName; private $useAbsoluteUrl; - private $router; + private ?CacheItemPoolInterface $cache; + private ?RouterInterface $router; + private bool $strictMode; - private string $manifestPath; - private string $entrypointsPath; + private ?string $viteMode = null; + private string $basePath; private $manifestData; private $entrypointsData; - private ?array $config = null; - private bool $strictMode; - private ?string $mode = null; public function __construct( string $publicPath, array $configs, string $defaultConfigName, bool $useAbsoluteUrl, + CacheItemPoolInterface $cache = null, RouterInterface $router = null, bool $strictMode = true ) { $this->publicPath = $publicPath; $this->configs = $configs; - $this->strictMode = $strictMode; + $this->configName = $defaultConfigName; $this->useAbsoluteUrl = $useAbsoluteUrl; + $this->cache = $cache; $this->router = $router; + $this->strictMode = $strictMode; - $this->setConfig($defaultConfigName); + $this->setConfig($this->configName); - if (($scheme = parse_url($this->manifestPath, \PHP_URL_SCHEME)) && 0 === strpos($scheme, 'http')) { + if (($scheme = parse_url($this->basePath.'manifest.json', \PHP_URL_SCHEME)) && 0 === strpos($scheme, 'http')) { throw new \Exception('You can\'t use a remote manifest with ViteAssetVersionStrategy'); } } public function setConfig(string $configName): void { - $this->mode = null; - $this->config = $this->configs[$configName]; - $this->manifestPath = $this->publicPath.$this->config['base'].'manifest.json'; - $this->entrypointsPath = $this->publicPath.$this->config['base'].'entrypoints.json'; + $this->viteMode = null; + $this->configName = $configName; + $this->basePath = $this->publicPath.$this->configs[$configName]['base']; } /** @@ -78,39 +81,65 @@ private function completeURL(string $path) private function getassetsPath(string $path): ?string { - if (null === $this->mode) { - if (!is_file($this->entrypointsPath)) { - throw new RuntimeException(sprintf('assets entrypoints file "%s" does not exist. Did you forget configure your `build_dir` in pentatrion_vite.yml?', $this->entrypointsPath)); + if (null === $this->viteMode) { + $manifestPath = $this->basePath.'manifest.json'; + $entrypointsPath = $this->basePath.'entrypoints.json'; + + $this->entrypointsData = null; + $this->manifestData = null; + + $this->viteMode = is_file($manifestPath) ? 'build' : 'dev'; + + if (!is_file($entrypointsPath)) { + throw new RuntimeException(sprintf('assets entrypoints file "%s" does not exist. Did you forget configure your `build_dir` in pentatrion_vite.yml?', $entrypointsPath)); } - if (is_file($this->manifestPath)) { - // when vite server is running manifest file doesn't exists - $this->mode = 'build'; + if ('build' === $this->viteMode && $this->cache) { + $entrypointsCacheItem = $this->cache->getItem("{$this->configName}.entrypoints"); + $manifestCacheItem = $this->cache->getItem("{$this->configName}.manifest"); + + if ($entrypointsCacheItem->isHit()) { + $this->entrypointsData = $entrypointsCacheItem->get(); + } + if ($manifestCacheItem->isHit()) { + $this->manifestData = $manifestCacheItem->get(); + } + } + + if ('build' === $this->viteMode && is_null($this->manifestData)) { try { - $this->manifestData = json_decode(file_get_contents($this->manifestPath), true, 512, \JSON_THROW_ON_ERROR); + $this->manifestData = json_decode(file_get_contents($manifestPath), true, 512, \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { - throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $this->manifestPath).$e->getMessage(), 0, $e); + throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $manifestPath).$e->getMessage(), 0, $e); } - } else { - $this->mode = 'dev'; + } + + if (is_null($this->entrypointsData)) { try { - $this->entrypointsData = json_decode(file_get_contents($this->entrypointsPath), true, 512, \JSON_THROW_ON_ERROR); + $this->entrypointsData = json_decode(file_get_contents($entrypointsPath), true, 512, \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { - throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $this->manifestPath).$e->getMessage(), 0, $e); + throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $manifestPath).$e->getMessage(), 0, $e); } } + + if (isset($entrypointsCacheItem)) { + $this->cache->save($entrypointsCacheItem->set($this->entrypointsData)); + } + if (isset($manifestCacheItem)) { + $this->cache->save($manifestCacheItem->set($this->manifestData)); + } } - if ('build' === $this->mode) { + if ('build' === $this->viteMode) { if (isset($this->manifestData[$path])) { - return $this->completeURL($this->config['base'].$this->manifestData[$path]['file']); + return $this->completeURL($this->basePath.$this->manifestData[$path]['file']); } } else { return $this->entrypointsData['viteServer'].$this->entrypointsData['base'].$path; } if ($this->strictMode) { - $message = sprintf('assets "%s" not found in manifest file "%s".', $path, $this->manifestPath); + $message = sprintf('assets "%s" not found in manifest file "%s".', $path, $manifestPath); $alternatives = $this->findAlternatives($path, $this->manifestData); if (\count($alternatives) > 0) { $message .= sprintf(' Did you mean one of these? "%s".', implode('", "', $alternatives)); diff --git a/src/CacheWarmer/EntrypointsCacheWarmer.php b/src/CacheWarmer/EntrypointsCacheWarmer.php index ebf24fb..a26d1ff 100644 --- a/src/CacheWarmer/EntrypointsCacheWarmer.php +++ b/src/CacheWarmer/EntrypointsCacheWarmer.php @@ -4,35 +4,50 @@ use Exception; use Pentatrion\ViteBundle\Asset\EntrypointsLookup; -use Pentatrion\ViteBundle\Exception\EntrypointsFileNotFoundException; +use Pentatrion\ViteBundle\Asset\ViteAssetVersionStrategy; use Symfony\Bundle\FrameworkBundle\CacheWarmer\AbstractPhpFileCacheWarmer; use Symfony\Component\Cache\Adapter\ArrayAdapter; class EntrypointsCacheWarmer extends AbstractPhpFileCacheWarmer { - private $basePaths; + private string $publicPath; + private array $configs; - public function __construct(array $basePaths, string $phpCacheFile) + public function __construct( + string $publicPath, + array $configs, + string $phpCacheFile) { - $this->basePaths = $basePaths; + $this->publicPath = $publicPath; + $this->configs = $configs; parent::__construct($phpCacheFile); } protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter): bool { - foreach ($this->basePaths as $basePath) { - $entrypointsPath = $basePath.'entrypoints.json'; + foreach ($this->configs as $configName => $config) { + $entrypointsPath = $this->publicPath.$this->configs[$configName]['base'].'entrypoints.json'; if (!file_exists($entrypointsPath)) { continue; } - $entrypointsLookup = new EntrypointsLookup($entrypointsPath); + $viteAssetVersionStrategy = new ViteAssetVersionStrategy( + $this->publicPath, + $this->configs, + $configName, + false, + $arrayAdapter, + null, + false + ); + // $entrypointsLookup = new EntrypointsLookup($basePath, $configName, false, $arrayAdapter); try { // any method that will call getFileContent and generate // the file in cache. - $entrypointsLookup->getBase(); - } catch (EntrypointsFileNotFoundException $e) { + // $entrypointsLookup->getBase(); + $viteAssetVersionStrategy->applyVersion('/some-dummy-path'); + } catch (\Exception $e) { // ignore exception } } diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index 9383e5b..d92554a 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -47,9 +47,12 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $lookupFactories = []; $tagRendererFactories = []; $configs = []; - $cacheKeys = []; foreach ($bundleConfig['configs'] as $configName => $config) { + if (!preg_match('/^[a-zA-Z_]+$/', $configName)) { + throw new \Exception('Invalid config name, you should use only a-z A-Z and _ characters.'); + } + $configs[$configName] = $configPrepared = self::prepareConfig($config); $lookupFactories[$configName] = $this->entrypointsLookupFactory( $container, @@ -58,7 +61,6 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $bundleConfig['cache'] ); $tagRendererFactories[$configName] = $this->tagRendererFactory($container, $configName, $configPrepared); - $cacheKeys[] = $this->resolveBasePath($container, $configPrepared); } } else { $defaultConfigName = '_default'; @@ -75,7 +77,6 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $tagRendererFactories = [ '_default' => $this->tagRendererFactory($container, $defaultConfigName, $configPrepared), ]; - $cacheKeys = [$this->resolveBasePath($container, $configPrepared)]; } if ('link-header' === $bundleConfig['preload']) { @@ -96,9 +97,6 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $container->getDefinition('pentatrion_vite.tag_renderer_collection') ->addArgument(ServiceLocatorTagPass::register($container, $tagRendererFactories)) ->addArgument($defaultConfigName); - - $container->getDefinition('pentatrion_vite.cache_warmer') - ->replaceArgument(0, $cacheKeys); } private function entrypointsLookupFactory( diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 478e4d9..3d1bb16 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -68,29 +68,33 @@ services: - "%pentatrion_vite.configs%" - "%pentatrion_vite.default_config%" - "%pentatrion_vite.absolute_url%" + - "@?pentatrion_vite.cache" - "@?router" - true + pentatrion_vite.preload_assets_event_listener: class: Pentatrion\ViteBundle\EventListener\PreloadAssetsEventListener tags: ["kernel.event_subscriber"] arguments: - "@pentatrion_vite.entrypoint_renderer" - pentatrion_vite.cache_warmer: - class: Pentatrion\ViteBundle\CacheWarmer\EntrypointsCacheWarmer - tags: ["kernel.cache_warmer"] - arguments: - - [] - - '%kernel.cache_dir%/pentatrion_vite.cache.php' pentatrion_vite.cache: class: Symfony\Component\Cache\Adapter\PhpArrayAdapter factory: [Symfony\Component\Cache\Adapter\PhpArrayAdapter, create] arguments: - '%kernel.cache_dir%/pentatrion_vite.cache.php' - - '@cache.pentatrion_vite' + - '@cache.pentatrion_vite_fallback' + + pentatrion_vite.cache_warmer: + class: Pentatrion\ViteBundle\CacheWarmer\EntrypointsCacheWarmer + tags: ["kernel.cache_warmer"] + arguments: + - "%kernel.project_dir%%pentatrion_vite.public_directory%" + - "%pentatrion_vite.configs%" + - '%kernel.cache_dir%/pentatrion_vite.cache.php' - cache.pentatrion_vite: + cache.pentatrion_vite_fallback: tags: ["cache.pool"] parent: cache.system \ No newline at end of file diff --git a/tests/Asset/EntrypointRendererTest.php b/tests/Asset/EntrypointRendererTest.php index 7ccbe0b..9d419b2 100644 --- a/tests/Asset/EntrypointRendererTest.php +++ b/tests/Asset/EntrypointRendererTest.php @@ -48,6 +48,7 @@ private function getEntrypointsLookup($prefix) { return new EntrypointsLookup( __DIR__.'/../fixtures/entrypoints/'.$prefix.'/', + '_default', true ); } diff --git a/tests/Asset/EntrypointsLookupTest.php b/tests/Asset/EntrypointsLookupTest.php index 451d744..0693298 100644 --- a/tests/Asset/EntrypointsLookupTest.php +++ b/tests/Asset/EntrypointsLookupTest.php @@ -12,6 +12,7 @@ private function getEntrypointsLookup($prefix) { return new EntrypointsLookup( __DIR__.'/../fixtures/entrypoints/'.$prefix.'/', + '_default', true ); } From 8353b6a3860e6dc95f265053c8af5ea8f0f8b924 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Thu, 2 Nov 2023 14:34:56 +0100 Subject: [PATCH 10/19] add FileAccessor for better readability with cache --- src/Asset/EntrypointRenderer.php | 2 +- src/Asset/EntrypointsLookup.php | 59 +++++----------- src/Asset/FileAccessor.php | 68 +++++++++++++++++++ src/Asset/ViteAssetVersionStrategy.php | 67 +++--------------- src/CacheWarmer/EntrypointsCacheWarmer.php | 32 ++++----- .../PentatrionViteExtension.php | 13 +--- src/Resources/config/services.yaml | 9 ++- tests/Asset/EntrypointRendererTest.php | 35 +++++++++- tests/Asset/EntrypointsLookupTest.php | 27 +++++++- 9 files changed, 174 insertions(+), 138 deletions(-) create mode 100644 src/Asset/FileAccessor.php diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index b3d78b0..fb4656c 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -210,7 +210,7 @@ public function renderLinks( $entrypointsLookup = $this->getEntrypointsLookup($configName); $tagRenderer = $this->getTagRenderer($configName); - if (!$entrypointsLookup->hasFile($configName)) { + if (!$entrypointsLookup->hasFile()) { return ''; } diff --git a/src/Asset/EntrypointsLookup.php b/src/Asset/EntrypointsLookup.php index f52bede..7ace319 100644 --- a/src/Asset/EntrypointsLookup.php +++ b/src/Asset/EntrypointsLookup.php @@ -3,74 +3,49 @@ namespace Pentatrion\ViteBundle\Asset; use Pentatrion\ViteBundle\Exception\EntrypointNotFoundException; -use Pentatrion\ViteBundle\Exception\EntrypointsFileNotFoundException; -use Psr\Cache\CacheItemPoolInterface; class EntrypointsLookup { private string $configName; private bool $throwOnMissingEntry; - private ?CacheItemPoolInterface $cache; + private FileAccessor $fileAccessor; - private array $fileInfos; + private ?array $fileContent = null; public function __construct( - string $basePath, + FileAccessor $fileAccessor, ?string $configName, // for cache to retrieve content : configName is cache key bool $throwOnMissingEntry = false, - CacheItemPoolInterface $cache = null ) { + $this->fileAccessor = $fileAccessor; $this->configName = $configName; $this->throwOnMissingEntry = $throwOnMissingEntry; - $this->cache = $cache; - $entrypointsPath = $basePath.'entrypoints.json'; - - $this->fileInfos = [ - 'entrypointsPath' => $entrypointsPath, - 'content' => null, - 'fileExists' => file_exists($entrypointsPath), - ]; } public function hasFile(): bool { - if (!isset($this->fileInfos)) { - return false; - } - - return $this->fileInfos['fileExists']; + return $this->fileAccessor->hasFile($this->configName, 'entrypoints'); } private function getFileContent(): array { - if ($this->cache) { - $entrypointsCacheItem = $this->cache->getItem("{$this->configName}.entrypoints"); + if (is_null($this->fileContent)) { + $this->fileContent = $this->fileAccessor->getData($this->configName, 'entrypoints'); - if ($entrypointsCacheItem->isHit()) { - $this->fileInfos['content'] = $entrypointsCacheItem->get(); - } - } - - if (!isset($this->fileInfos['content'])) { - if (!$this->fileInfos['fileExists']) { - throw new EntrypointsFileNotFoundException('entrypoints.json not found at '.$this->fileInfos['entrypointsPath']); - } - $content = json_decode(file_get_contents($this->fileInfos['entrypointsPath']), true); - if (!array_key_exists('entryPoints', $content) - || !array_key_exists('viteServer', $content) - || !array_key_exists('base', $content) + if (!array_key_exists('entryPoints', $this->fileContent) + || !array_key_exists('viteServer', $this->fileContent) + || !array_key_exists('base', $this->fileContent) ) { - throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints, base or viteServer not exists'); + throw new \Exception("$this->configName entrypoints.json : entryPoints, base or viteServer not exists"); } - - if (isset($entrypointsCacheItem)) { - $this->cache->save($entrypointsCacheItem->set($content)); - } - - $this->fileInfos['content'] = $content; } - return $this->fileInfos['content']; + return $this->fileContent; + } + + public function setFileContent($content) + { + $this->fileContent = $content; } public function getFileHash(string $filePath): ?string diff --git a/src/Asset/FileAccessor.php b/src/Asset/FileAccessor.php new file mode 100644 index 0000000..77a9140 --- /dev/null +++ b/src/Asset/FileAccessor.php @@ -0,0 +1,68 @@ + 'entrypoints.json', + 'manifest' => 'manifest.json', + ]; + + private array $configs; + private ?CacheItemPoolInterface $cache = null; + private array $content; + private string $publicPath; + + public function __construct( + string $publicPath, + array $configs, + CacheItemPoolInterface $cache = null + ) { + $this->publicPath = $publicPath; + $this->configs = $configs; + $this->cache = $cache; + } + + public function hasFile($configName, $fileType) + { + return file_exists($this->publicPath.$this->configs[$configName]['base'].self::FILES[$fileType]); + } + + public function getData($configName, $fileType) + { + if (!isset($this->content[$configName][$fileType])) { + if ($this->cache) { + $cacheItem = $this->cache->getItem("$configName.$fileType"); + + if ($cacheItem->isHit()) { + $this->content[$configName][$fileType] = $cacheItem->get(); + } + } + + if (!isset($this->content[$configName][$fileType])) { + $filePath = $this->publicPath.$this->configs[$configName]['base'].self::FILES[$fileType]; + + if (($scheme = parse_url($filePath, \PHP_URL_SCHEME)) && 0 === strpos($scheme, 'http')) { + throw new \Exception('You can\'t use a remote manifest with pentatrion/vite-bundle'); + } + + if (!file_exists($filePath)) { + throw new EntrypointsFileNotFoundException("$fileType not found at $filePath. Did you forget configure your `build_directory` in pentatrion_vite.yml"); + } + $content = json_decode(file_get_contents($filePath), true); + + if (isset($cacheItem)) { + $this->cache->save($cacheItem->set($content)); + } + + $this->content[$configName][$fileType] = $content; + } + } + + return $this->content[$configName][$fileType]; + } +} diff --git a/src/Asset/ViteAssetVersionStrategy.php b/src/Asset/ViteAssetVersionStrategy.php index 55445af..e044d9e 100644 --- a/src/Asset/ViteAssetVersionStrategy.php +++ b/src/Asset/ViteAssetVersionStrategy.php @@ -2,19 +2,16 @@ namespace Pentatrion\ViteBundle\Asset; -use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Asset\Exception\AssetNotFoundException; -use Symfony\Component\Asset\Exception\RuntimeException; use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; use Symfony\Component\Routing\RouterInterface; class ViteAssetVersionStrategy implements VersionStrategyInterface { - private string $publicPath; + private FileAccessor $fileAccessor; private array $configs; private string $configName; private $useAbsoluteUrl; - private ?CacheItemPoolInterface $cache; private ?RouterInterface $router; private bool $strictMode; @@ -24,34 +21,28 @@ class ViteAssetVersionStrategy implements VersionStrategyInterface private $entrypointsData; public function __construct( - string $publicPath, + FileAccessor $fileAccessor, array $configs, string $defaultConfigName, bool $useAbsoluteUrl, - CacheItemPoolInterface $cache = null, RouterInterface $router = null, bool $strictMode = true ) { - $this->publicPath = $publicPath; + $this->fileAccessor = $fileAccessor; $this->configs = $configs; $this->configName = $defaultConfigName; $this->useAbsoluteUrl = $useAbsoluteUrl; - $this->cache = $cache; $this->router = $router; $this->strictMode = $strictMode; $this->setConfig($this->configName); - - if (($scheme = parse_url($this->basePath.'manifest.json', \PHP_URL_SCHEME)) && 0 === strpos($scheme, 'http')) { - throw new \Exception('You can\'t use a remote manifest with ViteAssetVersionStrategy'); - } } public function setConfig(string $configName): void { $this->viteMode = null; $this->configName = $configName; - $this->basePath = $this->publicPath.$this->configs[$configName]['base']; + $this->basePath = $this->configs[$configName]['base']; } /** @@ -82,52 +73,10 @@ private function completeURL(string $path) private function getassetsPath(string $path): ?string { if (null === $this->viteMode) { - $manifestPath = $this->basePath.'manifest.json'; - $entrypointsPath = $this->basePath.'entrypoints.json'; - - $this->entrypointsData = null; - $this->manifestData = null; - - $this->viteMode = is_file($manifestPath) ? 'build' : 'dev'; + $this->viteMode = $this->fileAccessor->hasFile($this->configName, 'manifest') ? 'build' : 'dev'; - if (!is_file($entrypointsPath)) { - throw new RuntimeException(sprintf('assets entrypoints file "%s" does not exist. Did you forget configure your `build_dir` in pentatrion_vite.yml?', $entrypointsPath)); - } - - if ('build' === $this->viteMode && $this->cache) { - $entrypointsCacheItem = $this->cache->getItem("{$this->configName}.entrypoints"); - $manifestCacheItem = $this->cache->getItem("{$this->configName}.manifest"); - - if ($entrypointsCacheItem->isHit()) { - $this->entrypointsData = $entrypointsCacheItem->get(); - } - if ($manifestCacheItem->isHit()) { - $this->manifestData = $manifestCacheItem->get(); - } - } - - if ('build' === $this->viteMode && is_null($this->manifestData)) { - try { - $this->manifestData = json_decode(file_get_contents($manifestPath), true, 512, \JSON_THROW_ON_ERROR); - } catch (\JsonException $e) { - throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $manifestPath).$e->getMessage(), 0, $e); - } - } - - if (is_null($this->entrypointsData)) { - try { - $this->entrypointsData = json_decode(file_get_contents($entrypointsPath), true, 512, \JSON_THROW_ON_ERROR); - } catch (\JsonException $e) { - throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $manifestPath).$e->getMessage(), 0, $e); - } - } - - if (isset($entrypointsCacheItem)) { - $this->cache->save($entrypointsCacheItem->set($this->entrypointsData)); - } - if (isset($manifestCacheItem)) { - $this->cache->save($manifestCacheItem->set($this->manifestData)); - } + $this->manifestData = 'build' === $this->viteMode ? $this->fileAccessor->getData($this->configName, 'manifest') : null; + $this->entrypointsData = $this->fileAccessor->getData($this->configName, 'entrypoints'); } if ('build' === $this->viteMode) { @@ -139,7 +88,7 @@ private function getassetsPath(string $path): ?string } if ($this->strictMode) { - $message = sprintf('assets "%s" not found in manifest file "%s".', $path, $manifestPath); + $message = sprintf('assets "%s" not found in manifest file from config "%s".', $path, $this->configName); $alternatives = $this->findAlternatives($path, $this->manifestData); if (\count($alternatives) > 0) { $message .= sprintf(' Did you mean one of these? "%s".', implode('", "', $alternatives)); diff --git a/src/CacheWarmer/EntrypointsCacheWarmer.php b/src/CacheWarmer/EntrypointsCacheWarmer.php index a26d1ff..d189cdf 100644 --- a/src/CacheWarmer/EntrypointsCacheWarmer.php +++ b/src/CacheWarmer/EntrypointsCacheWarmer.php @@ -3,8 +3,7 @@ namespace Pentatrion\ViteBundle\CacheWarmer; use Exception; -use Pentatrion\ViteBundle\Asset\EntrypointsLookup; -use Pentatrion\ViteBundle\Asset\ViteAssetVersionStrategy; +use Pentatrion\ViteBundle\Asset\FileAccessor; use Symfony\Bundle\FrameworkBundle\CacheWarmer\AbstractPhpFileCacheWarmer; use Symfony\Component\Cache\Adapter\ArrayAdapter; @@ -25,28 +24,21 @@ public function __construct( protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter): bool { - foreach ($this->configs as $configName => $config) { - $entrypointsPath = $this->publicPath.$this->configs[$configName]['base'].'entrypoints.json'; + $fileAccessor = new FileAccessor($this->publicPath, $this->configs, $arrayAdapter); - if (!file_exists($entrypointsPath)) { - continue; + foreach ($this->configs as $configName => $config) { + try { + if ($fileAccessor->hasFile($configName, 'entrypoints')) { + $fileAccessor->getData($configName, 'entrypoints'); + } + } catch (\Exception $e) { + // ignore exception } - $viteAssetVersionStrategy = new ViteAssetVersionStrategy( - $this->publicPath, - $this->configs, - $configName, - false, - $arrayAdapter, - null, - false - ); - // $entrypointsLookup = new EntrypointsLookup($basePath, $configName, false, $arrayAdapter); try { - // any method that will call getFileContent and generate - // the file in cache. - // $entrypointsLookup->getBase(); - $viteAssetVersionStrategy->applyVersion('/some-dummy-path'); + if ($fileAccessor->hasFile($configName, 'manifest')) { + $fileAccessor->getData($configName, 'manifest'); + } } catch (\Exception $e) { // ignore exception } diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index d92554a..7bcef73 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -56,9 +56,7 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $configs[$configName] = $configPrepared = self::prepareConfig($config); $lookupFactories[$configName] = $this->entrypointsLookupFactory( $container, - $configName, - $configPrepared, - $bundleConfig['cache'] + $configName ); $tagRendererFactories[$configName] = $this->tagRendererFactory($container, $configName, $configPrepared); } @@ -69,9 +67,7 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $lookupFactories = [ '_default' => $this->entrypointsLookupFactory( $container, - $defaultConfigName, - $configPrepared, - $bundleConfig['cache'] + $defaultConfigName ), ]; $tagRendererFactories = [ @@ -102,15 +98,12 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void private function entrypointsLookupFactory( ContainerBuilder $container, string $configName, - array $config, - bool $cacheEnabled ): Reference { $id = $this->getServiceId('entrypoints_lookup', $configName); $arguments = [ - $this->resolveBasePath($container, $config), + new Reference('pentatrion_vite.file_accessor'), $configName, '%pentatrion_vite.throw_on_missing_entry%', - $cacheEnabled ? new Reference('pentatrion_vite.cache') : null, ]; $definition = new Definition(EntrypointsLookup::class, $arguments); $container->setDefinition($id, $definition); diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 3d1bb16..2940d65 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -64,11 +64,10 @@ services: # tags: # - { name: assets.package, package: vite } arguments: - - "%kernel.project_dir%%pentatrion_vite.public_directory%" + - "@pentatrion_vite.file_accessor" - "%pentatrion_vite.configs%" - "%pentatrion_vite.default_config%" - "%pentatrion_vite.absolute_url%" - - "@?pentatrion_vite.cache" - "@?router" - true @@ -79,6 +78,12 @@ services: arguments: - "@pentatrion_vite.entrypoint_renderer" + pentatrion_vite.file_accessor: + class: Pentatrion\ViteBundle\Asset\FileAccessor + arguments: + - "%kernel.project_dir%%pentatrion_vite.public_directory%" + - "%pentatrion_vite.configs%" + - "@pentatrion_vite.cache" pentatrion_vite.cache: class: Symfony\Component\Cache\Adapter\PhpArrayAdapter diff --git a/tests/Asset/EntrypointRendererTest.php b/tests/Asset/EntrypointRendererTest.php index 9d419b2..7c1e5a4 100644 --- a/tests/Asset/EntrypointRendererTest.php +++ b/tests/Asset/EntrypointRendererTest.php @@ -5,6 +5,7 @@ use Pentatrion\ViteBundle\Asset\EntrypointRenderer; use Pentatrion\ViteBundle\Asset\EntrypointsLookup; use Pentatrion\ViteBundle\Asset\EntrypointsLookupCollection; +use Pentatrion\ViteBundle\Asset\FileAccessor; use Pentatrion\ViteBundle\Asset\InlineContent; use Pentatrion\ViteBundle\Asset\TagRenderer; use Pentatrion\ViteBundle\Asset\TagRendererCollection; @@ -46,13 +47,43 @@ private function getEntrypointsLookupCollection(EntrypointsLookup $entrypointsLo private function getEntrypointsLookup($prefix) { + /** + * @var FileAccessor|Stub $fileAccessor + */ + $fileAccessor = $this->createStub(FileAccessor::class); + + $fileAccessor + ->method('getData') + ->willReturnCallback(function ($prefix, $fileType) { + $path = __DIR__.'/../fixtures/entrypoints/'.$prefix.'/'.$fileType.'.json'; + + return json_decode(file_get_contents($path), true); + }); + + $fileAccessor + ->method('hasFile') + ->willReturnCallback(function ($prefix, $fileType) { + $path = __DIR__.'/../fixtures/entrypoints/'.$prefix.'/'.$fileType.'.json'; + + return file_exists($path); + }); + return new EntrypointsLookup( - __DIR__.'/../fixtures/entrypoints/'.$prefix.'/', - '_default', + $fileAccessor, + $prefix, true ); } + // private function getEntrypointsLookup($prefix) + // { + // return new EntrypointsLookup( + // __DIR__.'/../fixtures/entrypoints/'.$prefix.'/', + // '_default', + // true + // ); + // } + public function basicProvider() { return [ diff --git a/tests/Asset/EntrypointsLookupTest.php b/tests/Asset/EntrypointsLookupTest.php index 0693298..e894e07 100644 --- a/tests/Asset/EntrypointsLookupTest.php +++ b/tests/Asset/EntrypointsLookupTest.php @@ -3,16 +3,39 @@ namespace Pentatrion\ViteBundle\Tests\Asset; use Pentatrion\ViteBundle\Asset\EntrypointsLookup; +use Pentatrion\ViteBundle\Asset\FileAccessor; use Pentatrion\ViteBundle\Exception\EntrypointNotFoundException; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\TestCase; class EntrypointsLookupTest extends TestCase { private function getEntrypointsLookup($prefix) { + /** + * @var FileAccessor|Stub $fileAccessor + */ + $fileAccessor = $this->createStub(FileAccessor::class); + + $fileAccessor + ->method('getData') + ->willReturnCallback(function ($prefix, $fileType) { + $path = __DIR__.'/../fixtures/entrypoints/'.$prefix.'/'.$fileType.'.json'; + + return json_decode(file_get_contents($path), true); + }); + + $fileAccessor + ->method('hasFile') + ->willReturnCallback(function ($prefix, $fileType) { + $path = __DIR__.'/../fixtures/entrypoints/'.$prefix.'/'.$fileType.'.json'; + + return file_exists($path); + }); + return new EntrypointsLookup( - __DIR__.'/../fixtures/entrypoints/'.$prefix.'/', - '_default', + $fileAccessor, + $prefix, true ); } From 66336cb87ea6472558537989af83e86ab23ab195 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Thu, 2 Nov 2023 15:43:31 +0100 Subject: [PATCH 11/19] fix github workflows --- .gitattributes | 2 + .github/workflows/ci.yaml | 22 +- .gitignore | 1 + composer.json | 9 +- composer.lock | 5477 ----------------- src/Asset/EntrypointsLookup.php | 2 +- .../PentatrionViteExtension.php | 2 +- 7 files changed, 20 insertions(+), 5495 deletions(-) delete mode 100644 composer.lock diff --git a/.gitattributes b/.gitattributes index aeaac3a..6e8c093 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ +/tests export-ignore +/phpunit.xml.dist export-ignore .github export-ignore .gitattributes export-ignore .gitignore export-ignore diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 94948bf..c7cf3f8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,29 +22,27 @@ jobs: - name: Lint PHP run: find -L . -path ./vendor -prune -o -type f -name '*.php' -print0 | xargs -0 -n 1 -P $(nproc) php -l - - name: Declare variables - if: matrix.php-versions == 8.1 - id: vars - run: | - echo "::set-output name=composer_cache_dir::$(composer config cache-files-dir)" + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache composer - if: matrix.php-versions == 8.1 uses: actions/cache@v3 with: - path: ${{ steps.vars.outputs.composer_cache_dir }} + path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-composer- + restore-keys: ${{ runner.os }}-composer- - name: Install dependencies - if: matrix.php-versions == 8.1 run: composer install --no-interaction --no-ansi - name: Validate coding standards - if: matrix.php-versions == 8.1 + if: matrix.php-versions == 8.2 run: php vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose --diff --dry-run --stop-on-violation --using-cache=no - name: Static analysis - if: matrix.php-versions == 8.1 run: php vendor/bin/phpstan analyse --configuration=phpstan.neon --verbose + + - name: Tests + if: matrix.php-versions == 8.2 + run: php bin/phpunit diff --git a/.gitignore b/.gitignore index 4e9c2f2..635a29a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /vendor /.php-cs-fixer.cache /.phpunit.result.cache +/composer.lock diff --git a/composer.json b/composer.json index 4104626..2cc11d9 100644 --- a/composer.json +++ b/composer.json @@ -43,11 +43,12 @@ "symfony/web-link": "^4.4 || ^5.0 || ^6.0 || ^7.0" }, "scripts": { - "cs-fix": "php8.1 vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php", + "cs-fix": "php8.2 vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php", "ci-check": [ - "find -L . -path ./vendor -prune -o -type f -name '*.php' -print0 | xargs -0 -n 1 -P $(nproc) php -l", - "php8.1 vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --diff --dry-run --stop-on-violation --using-cache=no", - "php8.1 vendor/bin/phpstan analyse --configuration=phpstan.neon" + "find -L . -path ./vendor -prune -o -type f -name '*.php' -print0 | xargs -0 -n 1 -P $(nproc) php7.4 -l", + "find -L . -path ./vendor -prune -o -type f -name '*.php' -print0 | xargs -0 -n 1 -P $(nproc) php8.2 -l", + "php8.2 vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --diff --dry-run --stop-on-violation --using-cache=no", + "php8.2 vendor/bin/phpstan analyse --configuration=phpstan.neon" ] } } \ No newline at end of file diff --git a/composer.lock b/composer.lock deleted file mode 100644 index e176f96..0000000 --- a/composer.lock +++ /dev/null @@ -1,5477 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "10c9d61736ec57babdfdb4c006dcc26b", - "packages": [ - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, - { - "name": "psr/container", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/2.0.2" - }, - "time": "2021-11-05T16:47:00+00:00" - }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Standard interfaces for event handling.", - "keywords": [ - "events", - "psr", - "psr-14" - ], - "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" - }, - "time": "2019-01-08T18:20:26+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": "symfony/asset", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/asset.git", - "reference": "b77a4cc8e266b7e0db688de740f9ee7253aa411c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/b77a4cc8e266b7e0db688de740f9ee7253aa411c", - "reference": "b77a4cc8e266b7e0db688de740f9ee7253aa411c", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "conflict": { - "symfony/http-foundation": "<5.4" - }, - "require-dev": { - "symfony/http-client": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Asset\\": "" - }, - "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": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/asset/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-04-21T14:41:17+00:00" - }, - { - "name": "symfony/cache", - "version": "v6.3.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "84aff8d948d6292d2b5a01ac622760be44dddc72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/84aff8d948d6292d2b5a01ac622760be44dddc72", - "reference": "84aff8d948d6292d2b5a01ac622760be44dddc72", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^2.0|^3.0", - "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^2.5|^3", - "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.3.6" - }, - "conflict": { - "doctrine/dbal": "<2.13.1", - "symfony/dependency-injection": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/var-dumper": "<5.4" - }, - "provide": { - "psr/cache-implementation": "2.0|3.0", - "psr/simple-cache-implementation": "1.0|2.0|3.0", - "symfony/cache-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/dbal": "^2.13.1|^3|^4", - "predis/predis": "^1.1|^2.0", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/filesystem": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "classmap": [ - "Traits/ValueWrapper.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", - "homepage": "https://symfony.com", - "keywords": [ - "caching", - "psr6" - ], - "support": { - "source": "https://github.com/symfony/cache/tree/v6.3.6" - }, - "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": "2023-10-17T14:44:58+00:00" - }, - { - "name": "symfony/cache-contracts", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache-contracts.git", - "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/ad945640ccc0ae6e208bcea7d7de4b39b569896b", - "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Cache\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to caching", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-23T14:45:45+00:00" - }, - { - "name": "symfony/config", - "version": "v6.3.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", - "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^5.4|^6.0", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/finder": "<5.4", - "symfony/service-contracts": "<2.5" - }, - "require-dev": { - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "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": "Helps you find, load, combine, autofill and validate configuration values of any kind", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/config/tree/v6.3.2" - }, - "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": "2023-07-19T20:22:16+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v6.3.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2ed62b3bf98346e1f45529a7b6be2196739bb993", - "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/service-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.2.10" - }, - "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<6.1", - "symfony/finder": "<5.4", - "symfony/proxy-manager-bridge": "<6.3", - "symfony/yaml": "<5.4" - }, - "provide": { - "psr/container-implementation": "1.1|2.0", - "symfony/service-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "symfony/config": "^6.1", - "symfony/expression-language": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "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": "Allows you to standardize and centralize the way objects are constructed in your application", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.3.5" - }, - "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": "2023-09-25T16:46:40+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-23T14:45:45+00:00" - }, - { - "name": "symfony/error-handler", - "version": "v6.3.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/error-handler.git", - "reference": "1f69476b64fb47105c06beef757766c376b548c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/1f69476b64fb47105c06beef757766c376b548c4", - "reference": "1f69476b64fb47105c06beef757766c376b548c4", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^5.4|^6.0" - }, - "conflict": { - "symfony/deprecation-contracts": "<2.5" - }, - "require-dev": { - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0" - }, - "bin": [ - "Resources/bin/patch-type-declarations" - ], - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\ErrorHandler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools to manage errors and ease debugging PHP code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.3.5" - }, - "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": "2023-09-12T06:57:20+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v6.3.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e", - "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/event-dispatcher-contracts": "^2.5|^3" - }, - "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/service-contracts": "<2.5" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0|3.0" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/error-handler": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2" - }, - "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": "2023-07-06T06:56:43+00:00" - }, - { - "name": "symfony/event-dispatcher-contracts", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/event-dispatcher": "^1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-23T14:45:45+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v6.3.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.3.1" - }, - "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": "2023-06-01T08:30:39+00:00" - }, - { - "name": "symfony/finder", - "version": "v6.3.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4", - "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "symfony/filesystem": "^6.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/v6.3.5" - }, - "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": "2023-09-26T12:56:25+00:00" - }, - { - "name": "symfony/framework-bundle", - "version": "v6.3.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/framework-bundle.git", - "reference": "dba20792c726c30d455626eddfb2db008f64085f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/dba20792c726c30d455626eddfb2db008f64085f", - "reference": "dba20792c726c30d455626eddfb2db008f64085f", - "shasum": "" - }, - "require": { - "composer-runtime-api": ">=2.1", - "ext-xml": "*", - "php": ">=8.1", - "symfony/cache": "^5.4|^6.0", - "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.3.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.1", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/filesystem": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/http-foundation": "^6.3", - "symfony/http-kernel": "^6.3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/routing": "^5.4|^6.0" - }, - "conflict": { - "doctrine/annotations": "<1.13.1", - "doctrine/persistence": "<1.3", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/asset": "<5.4", - "symfony/clock": "<6.3", - "symfony/console": "<5.4", - "symfony/dom-crawler": "<6.3", - "symfony/dotenv": "<5.4", - "symfony/form": "<5.4", - "symfony/http-client": "<6.3", - "symfony/lock": "<5.4", - "symfony/mailer": "<5.4", - "symfony/messenger": "<6.3", - "symfony/mime": "<6.2", - "symfony/property-access": "<5.4", - "symfony/property-info": "<5.4", - "symfony/security-core": "<5.4", - "symfony/security-csrf": "<5.4", - "symfony/serializer": "<6.3", - "symfony/stopwatch": "<5.4", - "symfony/translation": "<6.2.8", - "symfony/twig-bridge": "<5.4", - "symfony/twig-bundle": "<5.4", - "symfony/validator": "<6.3", - "symfony/web-profiler-bundle": "<5.4", - "symfony/workflow": "<5.4" - }, - "require-dev": { - "doctrine/annotations": "^1.13.1|^2", - "doctrine/persistence": "^1.3|^2|^3", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^5.4|^6.0", - "symfony/asset-mapper": "^6.3", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/clock": "^6.2", - "symfony/console": "^5.4.9|^6.0.9", - "symfony/css-selector": "^5.4|^6.0", - "symfony/dom-crawler": "^6.3", - "symfony/dotenv": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/html-sanitizer": "^6.1", - "symfony/http-client": "^6.3", - "symfony/lock": "^5.4|^6.0", - "symfony/mailer": "^5.4|^6.0", - "symfony/messenger": "^6.3", - "symfony/mime": "^6.2", - "symfony/notifier": "^5.4|^6.0", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^5.4|^6.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/rate-limiter": "^5.4|^6.0", - "symfony/scheduler": "^6.3", - "symfony/security-bundle": "^5.4|^6.0", - "symfony/semaphore": "^5.4|^6.0", - "symfony/serializer": "^6.3", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/string": "^5.4|^6.0", - "symfony/translation": "^6.2.8", - "symfony/twig-bundle": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^6.3", - "symfony/web-link": "^5.4|^6.0", - "symfony/workflow": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0", - "twig/twig": "^2.10|^3.0" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Symfony\\Bundle\\FrameworkBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.3.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": "2023-10-26T18:15:14+00:00" - }, - { - "name": "symfony/http-client", - "version": "v6.3.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-client.git", - "reference": "cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d", - "reference": "cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "^3", - "symfony/service-contracts": "^2.5|^3" - }, - "conflict": { - "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.3" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "1.0", - "symfony/http-client-implementation": "3.0" - }, - "require-dev": { - "amphp/amp": "^2.5", - "amphp/http-client": "^4.2.1", - "amphp/http-tunnel": "^1.0", - "amphp/socket": "^1.1", - "guzzlehttp/promises": "^1.4", - "nyholm/psr7": "^1.0", - "php-http/httplug": "^1.0|^2.0", - "psr/http-client": "^1.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/stopwatch": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpClient\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", - "homepage": "https://symfony.com", - "keywords": [ - "http" - ], - "support": { - "source": "https://github.com/symfony/http-client/tree/v6.3.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": "2023-10-29T12:41:36+00:00" - }, - { - "name": "symfony/http-client-contracts", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/3b66325d0176b4ec826bffab57c9037d759c31fb", - "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\HttpClient\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to HTTP clients", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-23T14:45:45+00:00" - }, - { - "name": "symfony/http-foundation", - "version": "v6.3.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "59d1837d5d992d16c2628cd0d6b76acf8d69b33e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/59d1837d5d992d16c2628cd0d6b76acf8d69b33e", - "reference": "59d1837d5d992d16c2628cd0d6b76acf8d69b33e", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" - }, - "conflict": { - "symfony/cache": "<6.3" - }, - "require-dev": { - "doctrine/dbal": "^2.13.1|^3|^4", - "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.3", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", - "symfony/mime": "^5.4|^6.0", - "symfony/rate-limiter": "^5.2|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "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": "Defines an object-oriented layer for the HTTP specification", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.3.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": "2023-10-28T23:55:27+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "v6.3.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "6d4098095f93279d9536a0e9124439560cc764d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6d4098095f93279d9536a0e9124439560cc764d0", - "reference": "6d4098095f93279d9536a0e9124439560cc764d0", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.3", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/http-foundation": "^6.3.4", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/browser-kit": "<5.4", - "symfony/cache": "<5.4", - "symfony/config": "<6.1", - "symfony/console": "<5.4", - "symfony/dependency-injection": "<6.3.4", - "symfony/doctrine-bridge": "<5.4", - "symfony/form": "<5.4", - "symfony/http-client": "<5.4", - "symfony/http-client-contracts": "<2.5", - "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4", - "symfony/translation": "<5.4", - "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<5.4", - "symfony/validator": "<5.4", - "symfony/var-dumper": "<6.3", - "twig/twig": "<2.13" - }, - "provide": { - "psr/log-implementation": "1.0|2.0|3.0" - }, - "require-dev": { - "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/clock": "^6.2", - "symfony/config": "^6.1", - "symfony/console": "^5.4|^6.0", - "symfony/css-selector": "^5.4|^6.0", - "symfony/dependency-injection": "^6.3.4", - "symfony/dom-crawler": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^5.4|^6.0", - "symfony/property-access": "^5.4.5|^6.0.5", - "symfony/routing": "^5.4|^6.0", - "symfony/serializer": "^6.3", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^6.3", - "symfony/var-exporter": "^6.2", - "twig/twig": "^2.13|^3.0.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a structured process for converting a Request into a Response", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.3.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": "2023-10-29T14:31:45+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-07-28T09:04:16+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-php83", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", - "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "symfony/polyfill-php80": "^1.14" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-08-16T06:22:46+00:00" - }, - { - "name": "symfony/routing", - "version": "v6.3.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/82616e59acd3e3d9c916bba798326cb7796d7d31", - "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "conflict": { - "doctrine/annotations": "<1.12", - "symfony/config": "<6.2", - "symfony/dependency-injection": "<5.4", - "symfony/yaml": "<5.4" - }, - "require-dev": { - "doctrine/annotations": "^1.12|^2", - "psr/log": "^1|^2|^3", - "symfony/config": "^6.2", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Routing\\": "" - }, - "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": "Maps an HTTP request to a set of configuration variables", - "homepage": "https://symfony.com", - "keywords": [ - "router", - "routing", - "uri", - "url" - ], - "support": { - "source": "https://github.com/symfony/routing/tree/v6.3.5" - }, - "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": "2023-09-20T16:05:51+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", - "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/container": "^2.0" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-23T14:45:45+00:00" - }, - { - "name": "symfony/translation-contracts", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/translation-contracts.git", - "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/02c24deb352fb0d79db5486c0c79905a85e37e86", - "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Translation\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to translation", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-30T17:17:10+00:00" - }, - { - "name": "symfony/twig-bridge", - "version": "v6.3.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bridge.git", - "reference": "18f2cbe1d46ad43c4d3bd45e5e6279172068e064" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/18f2cbe1d46ad43c4d3bd45e5e6279172068e064", - "reference": "18f2cbe1d46ad43c4d3bd45e5e6279172068e064", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/translation-contracts": "^2.5|^3", - "twig/twig": "^2.13|^3.0.4" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/console": "<5.4", - "symfony/form": "<6.3", - "symfony/http-foundation": "<5.4", - "symfony/http-kernel": "<6.2", - "symfony/mime": "<6.2", - "symfony/translation": "<5.4", - "symfony/workflow": "<5.4" - }, - "require-dev": { - "doctrine/annotations": "^1.12|^2", - "egulias/email-validator": "^2.1.10|^3|^4", - "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^5.4|^6.0", - "symfony/asset-mapper": "^6.3", - "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/form": "^6.3", - "symfony/html-sanitizer": "^6.1", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^6.2", - "symfony/intl": "^5.4|^6.0", - "symfony/mime": "^6.2", - "symfony/polyfill-intl-icu": "~1.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/routing": "^5.4|^6.0", - "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^5.4|^6.0", - "symfony/security-csrf": "^5.4|^6.0", - "symfony/security-http": "^5.4|^6.0", - "symfony/serializer": "^6.2", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^6.1", - "symfony/web-link": "^5.4|^6.0", - "symfony/workflow": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0", - "twig/cssinliner-extra": "^2.12|^3", - "twig/inky-extra": "^2.12|^3", - "twig/markdown-extra": "^2.12|^3" - }, - "type": "symfony-bridge", - "autoload": { - "psr-4": { - "Symfony\\Bridge\\Twig\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides integration for Twig with various Symfony components", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.3.5" - }, - "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": "2023-09-12T06:57:20+00:00" - }, - { - "name": "symfony/twig-bundle", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bundle.git", - "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", - "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", - "shasum": "" - }, - "require": { - "composer-runtime-api": ">=2.1", - "php": ">=8.1", - "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.1", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^6.2", - "symfony/twig-bridge": "^6.3", - "twig/twig": "^2.13|^3.0.4" - }, - "conflict": { - "symfony/framework-bundle": "<5.4", - "symfony/translation": "<5.4" - }, - "require-dev": { - "doctrine/annotations": "^1.10.4|^2", - "symfony/asset": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/routing": "^5.4|^6.0", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/web-link": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Symfony\\Bundle\\TwigBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a tight integration of Twig into the Symfony full-stack framework", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-06T09:53:41+00:00" - }, - { - "name": "symfony/var-dumper", - "version": "v6.3.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "999ede244507c32b8e43aebaa10e9fce20de7c97" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/999ede244507c32b8e43aebaa10e9fce20de7c97", - "reference": "999ede244507c32b8e43aebaa10e9fce20de7c97", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/console": "<5.4" - }, - "require-dev": { - "ext-iconv": "*", - "symfony/console": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", - "twig/twig": "^2.13|^3.0.4" - }, - "bin": [ - "Resources/bin/var-dump-server" - ], - "type": "library", - "autoload": { - "files": [ - "Resources/functions/dump.php" - ], - "psr-4": { - "Symfony\\Component\\VarDumper\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides mechanisms for walking through any arbitrary PHP variable", - "homepage": "https://symfony.com", - "keywords": [ - "debug", - "dump" - ], - "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.3.6" - }, - "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": "2023-10-12T18:45:56+00:00" - }, - { - "name": "symfony/var-exporter", - "version": "v6.3.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-exporter.git", - "reference": "374d289c13cb989027274c86206ddc63b16a2441" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/374d289c13cb989027274c86206ddc63b16a2441", - "reference": "374d289c13cb989027274c86206ddc63b16a2441", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "symfony/var-dumper": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\VarExporter\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows exporting any serializable PHP data structure to plain PHP code", - "homepage": "https://symfony.com", - "keywords": [ - "clone", - "construct", - "export", - "hydrate", - "instantiate", - "lazy-loading", - "proxy", - "serialize" - ], - "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.3.6" - }, - "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": "2023-10-13T09:16:49+00:00" - }, - { - "name": "twig/twig", - "version": "v3.7.1", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" - }, - "require-dev": { - "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "role": "Contributors" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "support": { - "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.1" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2023-08-28T11:09:02+00:00" - } - ], - "packages-dev": [ - { - "name": "composer/pcre", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Pcre\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", - "keywords": [ - "PCRE", - "preg", - "regex", - "regular expression" - ], - "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.1" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2023-10-11T07:11:09+00:00" - }, - { - "name": "composer/semver", - "version": "3.4.0", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2023-08-31T09:50:34+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", - "shasum": "" - }, - "require": { - "composer/pcre": "^1 || ^2 || ^3", - "php": "^7.2.5 || ^8.0", - "psr/log": "^1 || ^2 || ^3" - }, - "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-02-25T21:32:43+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:23:10+00:00" - }, - { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.37.1", - "source": { - "type": "git", - "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "c3fe76976081ab871aa654e872da588077e19679" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/c3fe76976081ab871aa654e872da588077e19679", - "reference": "c3fe76976081ab871aa654e872da588077e19679", - "shasum": "" - }, - "require": { - "composer/semver": "^3.3", - "composer/xdebug-handler": "^3.0.3", - "ext-json": "*", - "ext-tokenizer": "*", - "php": "^7.4 || ^8.0", - "sebastian/diff": "^4.0 || ^5.0", - "symfony/console": "^5.4 || ^6.0", - "symfony/event-dispatcher": "^5.4 || ^6.0", - "symfony/filesystem": "^5.4 || ^6.0", - "symfony/finder": "^5.4 || ^6.0", - "symfony/options-resolver": "^5.4 || ^6.0", - "symfony/polyfill-mbstring": "^1.27", - "symfony/polyfill-php80": "^1.27", - "symfony/polyfill-php81": "^1.27", - "symfony/process": "^5.4 || ^6.0", - "symfony/stopwatch": "^5.4 || ^6.0" - }, - "require-dev": { - "facile-it/paraunit": "^1.3 || ^2.0", - "justinrainbow/json-schema": "^5.2", - "keradus/cli-executor": "^2.0", - "mikey179/vfsstream": "^1.6.11", - "php-coveralls/php-coveralls": "^2.5.3", - "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", - "phpspec/prophecy": "^1.16", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "symfony/phpunit-bridge": "^6.2.3", - "symfony/yaml": "^5.4 || ^6.0" - }, - "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters." - }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", - "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" - } - ], - "description": "A tool to automatically fix PHP code style", - "keywords": [ - "Static code analysis", - "fixer", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.37.1" - }, - "funding": [ - { - "url": "https://github.com/keradus", - "type": "github" - } - ], - "time": "2023-10-29T20:51:23+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": "v4.17.1", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.0" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-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/v4.17.1" - }, - "time": "2023-08-13T19:53:39+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "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.3" - }, - "time": "2021-07-20T11:28:43+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.10.40", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/93c84b5bf7669920d823631e39904d69b9c7dc5d", - "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" - } - ], - "time": "2023-10-30T14:48:31+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "9.2.29", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "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-master": "9.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 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/9.2.29" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-09-19T04:57:46+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "3.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "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": "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", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-12-02T12:48:52+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.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": "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/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "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": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "5.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "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/5.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:16:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "9.6.13", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.3.1 || ^2", - "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": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.6-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/9.6.13" - }, - "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": "2023-09-19T05:39:22+00:00" - }, - { - "name": "psr/link", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/link.git", - "reference": "84b159194ecfd7eaa472280213976e96415433f7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/link/zipball/84b159194ecfd7eaa472280213976e96415433f7", - "reference": "84b159194ecfd7eaa472280213976e96415433f7", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "suggest": { - "fig/link-util": "Provides some useful PSR-13 utilities" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Link\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interfaces for HTTP links", - "homepage": "https://github.com/php-fig/link", - "keywords": [ - "http", - "http-link", - "link", - "psr", - "psr-13", - "rest" - ], - "support": { - "source": "https://github.com/php-fig/link/tree/2.0.1" - }, - "time": "2021-03-11T23:00:27+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.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", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.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/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.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/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" - }, - { - "name": "sebastian/comparator", - "version": "4.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.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", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T12:41:17+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "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 calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T15:52:27+00:00" - }, - { - "name": "sebastian/diff", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-05-07T05:35:17+00:00" - }, - { - "name": "sebastian/environment", - "version": "5.1.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.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": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:03:51+00:00" - }, - { - "name": "sebastian/exporter", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T06:03:37+00:00" - }, - { - "name": "sebastian/global-state", - "version": "5.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "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": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-02T09:26:13+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.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", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-28T06:42:11+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.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/4.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:12:34+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.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/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:14:26+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.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/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "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": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:45:17+00:00" - }, - { - "name": "sebastian/type", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "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": "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/3.2.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:13:03+00:00" - }, - { - "name": "sebastian/version", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "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": "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/3.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" - }, - { - "name": "symfony/console", - "version": "v6.3.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6", - "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0" - }, - "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" - }, - "provide": { - "psr/log-implementation": "1.0|2.0|3.0" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/lock": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com", - "keywords": [ - "cli", - "command-line", - "console", - "terminal" - ], - "support": { - "source": "https://github.com/symfony/console/tree/v6.3.4" - }, - "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": "2023-08-16T10:10:12+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-12T14:21:09+00:00" - }, - { - "name": "symfony/phpunit-bridge", - "version": "v6.3.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "c6f1df6a76c2c12bd14a0a5bf7c556dd935efe1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/c6f1df6a76c2c12bd14a0a5bf7c556dd935efe1d", - "reference": "c6f1df6a76c2c12bd14a0a5bf7c556dd935efe1d", - "shasum": "" - }, - "require": { - "php": ">=7.1.3" - }, - "conflict": { - "phpunit/phpunit": "<7.5|9.1.2" - }, - "require-dev": { - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/error-handler": "^5.4|^6.0", - "symfony/polyfill-php81": "^1.27" - }, - "bin": [ - "bin/simple-phpunit" - ], - "type": "symfony-bridge", - "extra": { - "thanks": { - "name": "phpunit/phpunit", - "url": "https://github.com/sebastianbergmann/phpunit" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Bridge\\PhpUnit\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.3.6" - }, - "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": "2023-10-12T15:02:41+00:00" - }, - { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "875e90aeea2777b6f135677f618529449334a612" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", - "reference": "875e90aeea2777b6f135677f618529449334a612", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's grapheme_* functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-php81", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/process", - "version": "v6.3.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54", - "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "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/v6.3.4" - }, - "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": "2023-08-07T10:39:22+00:00" - }, - { - "name": "symfony/stopwatch", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", - "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/service-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a way to profile code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-02-16T10:14:28+00:00" - }, - { - "name": "symfony/string", - "version": "v6.3.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339", - "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/translation-contracts": "<2.5" - }, - "require-dev": { - "symfony/error-handler": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/intl": "^6.2", - "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v6.3.5" - }, - "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": "2023-09-18T10:38:32+00:00" - }, - { - "name": "symfony/web-link", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/web-link.git", - "reference": "0989ca617d0703cdca501a245f10e194ff22315b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/web-link/zipball/0989ca617d0703cdca501a245f10e194ff22315b", - "reference": "0989ca617d0703cdca501a245f10e194ff22315b", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/link": "^1.1|^2.0" - }, - "conflict": { - "symfony/http-kernel": "<5.4" - }, - "provide": { - "psr/link-implementation": "1.0|2.0" - }, - "require-dev": { - "symfony/http-kernel": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\WebLink\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kévin Dunglas", - "email": "dunglas@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Manages links between resources", - "homepage": "https://symfony.com", - "keywords": [ - "dns-prefetch", - "http", - "http2", - "link", - "performance", - "prefetch", - "preload", - "prerender", - "psr13", - "push" - ], - "support": { - "source": "https://github.com/symfony/web-link/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-04-21T14:41:17+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", - "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.1" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2021-07-28T10:34:58+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^7.4 || ^8.0" - }, - "platform-dev": [], - "plugin-api-version": "2.3.0" -} diff --git a/src/Asset/EntrypointsLookup.php b/src/Asset/EntrypointsLookup.php index 7ace319..cf1f5f9 100644 --- a/src/Asset/EntrypointsLookup.php +++ b/src/Asset/EntrypointsLookup.php @@ -15,7 +15,7 @@ class EntrypointsLookup public function __construct( FileAccessor $fileAccessor, ?string $configName, // for cache to retrieve content : configName is cache key - bool $throwOnMissingEntry = false, + bool $throwOnMissingEntry = false ) { $this->fileAccessor = $fileAccessor; $this->configName = $configName; diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index 7bcef73..88098b3 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -97,7 +97,7 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void private function entrypointsLookupFactory( ContainerBuilder $container, - string $configName, + string $configName ): Reference { $id = $this->getServiceId('entrypoints_lookup', $configName); $arguments = [ From aea9ce7bcf0ff73ed58489b6a74587b6a83888ca Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Thu, 2 Nov 2023 20:09:51 +0100 Subject: [PATCH 12/19] improve github ci --- .github/workflows/ci.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c7cf3f8..1f5e6bc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,12 +1,16 @@ name: CI -on: [ push, pull_request ] +on: + push: + branches: ['main'] + pull_request: jobs: ci: name: CI runs-on: ubuntu-20.04 strategy: + fail-fast: false matrix: php-versions: [ '7.4', '8.0', '8.1', '8.2' ] @@ -23,10 +27,12 @@ jobs: run: find -L . -path ./vendor -prune -o -type f -name '*.php' -print0 | xargs -0 -n 1 -P $(nproc) php -l - name: Get composer cache directory + # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache composer + # https://github.com/shivammathur/setup-php/tree/v2/#cache-composer-dependencies uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} From 7666a66a12e4b9055be9f9ceb7b3b07961ab617a Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 3 Nov 2023 07:33:03 +0100 Subject: [PATCH 13/19] add playgrounds install commands --- src/DependencyInjection/PentatrionViteExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index 88098b3..a18c36b 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -49,7 +49,7 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $configs = []; foreach ($bundleConfig['configs'] as $configName => $config) { - if (!preg_match('/^[a-zA-Z_]+$/', $configName)) { + if (!preg_match('/^[0-9a-zA-Z_]+$/', $configName)) { throw new \Exception('Invalid config name, you should use only a-z A-Z and _ characters.'); } From c1ec656d3b68ea1a63ad83cc7d19388323ba824b Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 3 Nov 2023 07:45:18 +0100 Subject: [PATCH 14/19] merge github workflows --- .github/workflows/ci.yaml | 54 --------------------------------------- 1 file changed, 54 deletions(-) delete mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index 1f5e6bc..0000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: CI - -on: - push: - branches: ['main'] - pull_request: - -jobs: - ci: - name: CI - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - php-versions: [ '7.4', '8.0', '8.1', '8.2' ] - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - - - name: Lint PHP - run: find -L . -path ./vendor -prune -o -type f -name '*.php' -print0 | xargs -0 -n 1 -P $(nproc) php -l - - - name: Get composer cache directory - # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache composer - # https://github.com/shivammathur/setup-php/tree/v2/#cache-composer-dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Install dependencies - run: composer install --no-interaction --no-ansi - - - name: Validate coding standards - if: matrix.php-versions == 8.2 - run: php vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose --diff --dry-run --stop-on-violation --using-cache=no - - - name: Static analysis - run: php vendor/bin/phpstan analyse --configuration=phpstan.neon --verbose - - - name: Tests - if: matrix.php-versions == 8.2 - run: php bin/phpunit From ff1531ac38d013e1352d02db4b65e77a164b572c Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 3 Nov 2023 09:27:04 +0100 Subject: [PATCH 15/19] add github issue templates --- .github/ISSUE_TEMPLATE/bug_report.yaml | 54 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yaml | 1 + .github/ISSUE_TEMPLATE/feature_request.yaml | 17 +++++++ 3 files changed, 72 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml create mode 100644 .github/ISSUE_TEMPLATE/config.yaml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yaml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..906b1cb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,54 @@ +name: 🐛 Bug report +description: Create a report to help us improve +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for using this bundle and taking the time to fill out this bug report ! + - type: input + id: vite-bundle-version + attributes: + label: vite-bundle version + description: composer show pentatrion/vite-bundle | grep versions + placeholder: x.y.z + validations: + required: true + - type: input + id: vite-plugin-symfony-version + attributes: + label: vite-plugin-symfony version + description: npm list vite-plugin-symfony + placeholder: x.y.z + validations: + required: true + - type: input + id: context + attributes: + label: Symfony version, PHP version, your OS (node version ?) + placeholder: "symfony 7.3, PHP 8.2, node 20.5, OS Linux" + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the problem + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce + description: | + ⚠️ This is the most important part of the report ⚠️ + Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix. + Please, take the time to show us some code and/or config that is needed for others to reproduce the problem easily. + validations: + required: true + - type: textarea + id: possible-solution + attributes: + label: Possible Solution + description: | + Optional: only if you have suggestions on a fix/reason for the bug + Don't hesitate to create a pull request with your solution, it helps get faster feedback. You should open a pull request on the main symfony-vite-dev monorepo : https://github.com/lhapaipai/symfony-vite-dev. + This repository is a "subtree split": a read-only subset of that main repository. diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 0000000..a49eab2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1 @@ +blank_issues_enabled: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 0000000..52b3de7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,17 @@ +name: 🚀 Feature Request +description: RFC and ideas for new features and improvements +body: + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the new feature + validations: + required: true + - type: textarea + id: example + attributes: + label: Example + description: | + A simple example of the new feature in action (include PHP code, YAML config, etc.) + If the new feature changes an existing feature, include a simple before/after comparison. From 48bfaf7445138b765558ea5c6572473585c04006 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 3 Nov 2023 09:40:41 +0100 Subject: [PATCH 16/19] update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 95bf7fa..bab97d6 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ This bundle helping you render all of the dynamic `script` and `link` tags needed. Essentially, he provides two twig functions to load the correct scripts into your templates. +⚠️ This repository is a "subtree split": a read-only subset of that main repository [symfony-vite-dev](https://github.com/lhapaipai/symfony-vite-dev). + ## Installation Install the bundle with : @@ -45,7 +47,6 @@ Add this twig functions in any template or base layout where you need to include | ----------------------------------------------------------------------- | :------------------------ | | [vite-bundle](https://github.com/lhapaipai/vite-bundle) | Symfony Bundle | | [vite-plugin-symfony](https://github.com/lhapaipai/vite-plugin-symfony) | Vite plugin | -| [symfony-vite-docs](https://github.com/lhapaipai/symfony-vite-docs) | Documentation | | [symfony-vite-dev](https://github.com/lhapaipai/symfony-vite-dev) | Package for contributors | ## License From 8c24dc009d5d6a4920e540c68385a274d228d95b Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 3 Nov 2023 10:36:40 +0100 Subject: [PATCH 17/19] add symfony64/symfony7 skeletons --- src/DependencyInjection/PentatrionViteExtension.php | 5 +++++ src/Resources/config/services.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index a18c36b..c2eb44e 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -93,6 +93,11 @@ public function load(array $bundleConfigs, ContainerBuilder $container): void $container->getDefinition('pentatrion_vite.tag_renderer_collection') ->addArgument(ServiceLocatorTagPass::register($container, $tagRendererFactories)) ->addArgument($defaultConfigName); + + if ($bundleConfig['cache']) { + $container->getDefinition('pentatrion_vite.file_accessor') + ->replaceArgument(2, new Reference('pentatrion_vite.cache')); + } } private function entrypointsLookupFactory( diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 2940d65..f77273f 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -83,7 +83,7 @@ services: arguments: - "%kernel.project_dir%%pentatrion_vite.public_directory%" - "%pentatrion_vite.configs%" - - "@pentatrion_vite.cache" + - null pentatrion_vite.cache: class: Symfony\Component\Cache\Adapter\PhpArrayAdapter From b31dbb8a6dcb88cd89fca6dbdfab55a8e394d007 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 3 Nov 2023 11:30:08 +0100 Subject: [PATCH 18/19] allow symfony7 --- src/Asset/EntrypointRenderer.php | 28 +++++++++++++------ src/Asset/EntrypointsLookup.php | 18 ++++++------ src/Asset/FileAccessor.php | 4 +-- src/Asset/InlineContent.php | 4 +-- src/Asset/Tag.php | 6 ++-- src/Asset/TagRenderer.php | 16 +++++------ src/Asset/ViteAssetVersionStrategy.php | 2 +- src/CacheWarmer/EntrypointsCacheWarmer.php | 2 +- src/Controller/ViteController.php | 2 +- .../PentatrionViteExtension.php | 13 +-------- .../PreloadAssetsEventListener.php | 2 +- src/Resources/config/services.yaml | 2 -- src/Twig/EntryFilesTwigExtension.php | 12 ++++---- 13 files changed, 54 insertions(+), 57 deletions(-) diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index fb4656c..b80a8ae 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -50,7 +50,7 @@ private function getTagRenderer(string $configName = null): TagRenderer return $this->tagRendererCollection->getTagRenderer($configName); } - private function completeURL(string $path, $useAbsoluteUrl = false) + private function completeURL(string $path, bool $useAbsoluteUrl = false): string { if (false === $useAbsoluteUrl || null === $this->router) { return $path; @@ -59,7 +59,7 @@ private function completeURL(string $path, $useAbsoluteUrl = false) return $this->router->getContext()->getScheme().'://'.$this->router->getContext()->getHost().$path; } - private function shouldUseAbsoluteURL(array $options, $configName) + private function shouldUseAbsoluteURL(array $options, string $configName = null): bool { $viteServer = $this->getEntrypointsLookup($configName)->getViteServer($configName); @@ -98,12 +98,15 @@ public function getRenderedStyles(): array return $this->renderedFiles['styles']; } + /** + * @return string|array + */ public function renderScripts( string $entryName, array $options = [], - $configName = null, - $toString = true - ): string { + string $configName = null, + bool $toString = true + ): mixed { $entrypointsLookup = $this->getEntrypointsLookup($configName); $tagRenderer = $this->getTagRenderer($configName); @@ -201,12 +204,15 @@ public function renderScripts( return $this->renderTags($tags, $isBuild, $toString); } + /** + * @return string|array + */ public function renderLinks( string $entryName, array $options = [], - $configName = null, - $toString = true - ): string { + string $configName = null, + bool $toString = true + ): mixed { $entrypointsLookup = $this->getEntrypointsLookup($configName); $tagRenderer = $this->getTagRenderer($configName); @@ -256,7 +262,11 @@ public function renderLinks( return $this->renderTags($tags, $isBuild, $toString); } - public function renderTags(array $tags, $isBuild, $toString) + + /** + * @return string|array + */ + public function renderTags(array $tags, bool $isBuild, bool $toString): mixed { if (null !== $this->eventDispatcher) { foreach ($tags as $tag) { diff --git a/src/Asset/EntrypointsLookup.php b/src/Asset/EntrypointsLookup.php index cf1f5f9..9d12de1 100644 --- a/src/Asset/EntrypointsLookup.php +++ b/src/Asset/EntrypointsLookup.php @@ -43,7 +43,7 @@ private function getFileContent(): array return $this->fileContent; } - public function setFileContent($content) + public function setFileContent(string $content): void { $this->fileContent = $content; } @@ -71,45 +71,45 @@ public function isBuild(): bool return null === $this->getFileContent()['viteServer']; } - public function getViteServer() + public function getViteServer(): ?string { return $this->getFileContent()['viteServer']; } - public function getBase() + public function getBase(): string { return $this->getFileContent()['base']; } - public function getJSFiles($entryName): array + public function getJSFiles(string $entryName): array { $this->throwIfEntrypointIsMissing($entryName); return $this->getFileContent()['entryPoints'][$entryName]['js'] ?? []; } - public function getCSSFiles($entryName): array + public function getCSSFiles(string $entryName): array { $this->throwIfEntrypointIsMissing($entryName); return $this->getFileContent()['entryPoints'][$entryName]['css'] ?? []; } - public function getJavascriptDependencies($entryName): array + public function getJavascriptDependencies(string $entryName): array { $this->throwIfEntrypointIsMissing($entryName); return $this->getFileContent()['entryPoints'][$entryName]['preload'] ?? []; } - public function getJavascriptDynamicDependencies($entryName): array + public function getJavascriptDynamicDependencies(string $entryName): array { $this->throwIfEntrypointIsMissing($entryName); return $this->getFileContent()['entryPoints'][$entryName]['dynamic'] ?? []; } - public function hasLegacy($entryName): bool + public function hasLegacy(string $entryName): bool { $this->throwIfEntrypointIsMissing($entryName); @@ -118,7 +118,7 @@ public function hasLegacy($entryName): bool return isset($entryInfos['entryPoints'][$entryName]['legacy']) && false !== $entryInfos['entryPoints'][$entryName]['legacy']; } - public function getLegacyJSFile($entryName): string + public function getLegacyJSFile(string $entryName): string { $this->throwIfEntrypointIsMissing($entryName); diff --git a/src/Asset/FileAccessor.php b/src/Asset/FileAccessor.php index 77a9140..3e97a64 100644 --- a/src/Asset/FileAccessor.php +++ b/src/Asset/FileAccessor.php @@ -27,12 +27,12 @@ public function __construct( $this->cache = $cache; } - public function hasFile($configName, $fileType) + public function hasFile(string $configName, string $fileType): bool { return file_exists($this->publicPath.$this->configs[$configName]['base'].self::FILES[$fileType]); } - public function getData($configName, $fileType) + public function getData(string $configName, string $fileType): array { if (!isset($this->content[$configName][$fileType])) { if ($this->cache) { diff --git a/src/Asset/InlineContent.php b/src/Asset/InlineContent.php index db7799e..d4fa90b 100644 --- a/src/Asset/InlineContent.php +++ b/src/Asset/InlineContent.php @@ -36,14 +36,14 @@ class InlineContent })();\n INLINE; - public static function getSystemJSInlineCode($id): string + public static function getSystemJSInlineCode(string $id): string { $content = 'System.import(document.getElementById("__ID__").getAttribute("data-src"))'; return str_replace('__ID__', $id, $content); } - public static function getReactRefreshInlineCode(string $devServerUrl) + public static function getReactRefreshInlineCode(string $devServerUrl): string { return <<tagName = $tagName; $this->attributes = $attributes; @@ -54,7 +54,7 @@ public function getAttributes(): array return $this->attributes; } - public function getAttribute($key): mixed + public function getAttribute(string $key): mixed { return key_exists($key, $this->attributes) ? $this->attributes[$key] : null; } @@ -63,7 +63,7 @@ public function getAttribute($key): mixed * @param string $name The attribute name * @param string|bool $value Value can be "true" to have an attribute without a value (e.g. "defer") */ - public function setAttribute(string $name, $value): self + public function setAttribute(string $name, mixed $value): self { $this->attributes[$name] = $value; diff --git a/src/Asset/TagRenderer.php b/src/Asset/TagRenderer.php index 4d777e8..1051c6e 100644 --- a/src/Asset/TagRenderer.php +++ b/src/Asset/TagRenderer.php @@ -8,14 +8,14 @@ class TagRenderer private array $globalLinkAttributes; public function __construct( - $scriptAttributes = [], - $linkAttributes = [] + array $scriptAttributes = [], + array $linkAttributes = [] ) { $this->globalScriptAttributes = $scriptAttributes; $this->globalLinkAttributes = $linkAttributes; } - public function createViteClientScript($src): Tag + public function createViteClientScript(string $src): Tag { return $this->createInternalScriptTag( [ @@ -25,7 +25,7 @@ public function createViteClientScript($src): Tag ); } - public function createReactRefreshScript($devServerUrl): Tag + public function createReactRefreshScript(string $devServerUrl): Tag { return $this->createInternalScriptTag( ['type' => 'module'], @@ -57,7 +57,7 @@ public function createDetectModernBrowserScript(): Tag ); } - public function createInternalScriptTag($attributes = [], $content = ''): Tag + public function createInternalScriptTag(array $attributes = [], string $content = ''): Tag { $tag = new Tag( Tag::SCRIPT_TAG, @@ -69,7 +69,7 @@ public function createInternalScriptTag($attributes = [], $content = ''): Tag return $tag; } - public function createScriptTag($attributes = [], $content = ''): Tag + public function createScriptTag(array $attributes = [], string $content = ''): Tag { $tag = new Tag( Tag::SCRIPT_TAG, @@ -80,7 +80,7 @@ public function createScriptTag($attributes = [], $content = ''): Tag return $tag; } - public function createLinkStylesheetTag($fileName, $extraAttributes = []): Tag + public function createLinkStylesheetTag(string $fileName, array $extraAttributes = []): Tag { $attributes = [ 'rel' => 'stylesheet', @@ -95,7 +95,7 @@ public function createLinkStylesheetTag($fileName, $extraAttributes = []): Tag return $tag; } - public function createModulePreloadLinkTag($fileName, $extraAttributes = []): Tag + public function createModulePreloadLinkTag(string $fileName, array $extraAttributes = []): Tag { $attributes = [ 'rel' => 'modulepreload', diff --git a/src/Asset/ViteAssetVersionStrategy.php b/src/Asset/ViteAssetVersionStrategy.php index e044d9e..f946855 100644 --- a/src/Asset/ViteAssetVersionStrategy.php +++ b/src/Asset/ViteAssetVersionStrategy.php @@ -61,7 +61,7 @@ public function applyVersion(string $path): string return $this->getassetsPath($path) ?: $path; } - private function completeURL(string $path) + private function completeURL(string $path): string { if (false === $this->useAbsoluteUrl || null === $this->router) { return $path; diff --git a/src/CacheWarmer/EntrypointsCacheWarmer.php b/src/CacheWarmer/EntrypointsCacheWarmer.php index d189cdf..16d7ceb 100644 --- a/src/CacheWarmer/EntrypointsCacheWarmer.php +++ b/src/CacheWarmer/EntrypointsCacheWarmer.php @@ -22,7 +22,7 @@ public function __construct( parent::__construct($phpCacheFile); } - protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter): bool + protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter, string $buildDir = null): bool { $fileAccessor = new FileAccessor($this->publicPath, $this->configs, $arrayAdapter); diff --git a/src/Controller/ViteController.php b/src/Controller/ViteController.php index 3a5d378..3dd0f93 100644 --- a/src/Controller/ViteController.php +++ b/src/Controller/ViteController.php @@ -29,7 +29,7 @@ public function __construct( $this->proxyOrigin = $proxyOrigin; } - public function proxyBuild($path, $configName = null): Response + public function proxyBuild(string $path, string $configName = null): Response { if (is_null($configName)) { $configName = $this->defaultConfig; diff --git a/src/DependencyInjection/PentatrionViteExtension.php b/src/DependencyInjection/PentatrionViteExtension.php index c2eb44e..9ce41a3 100644 --- a/src/DependencyInjection/PentatrionViteExtension.php +++ b/src/DependencyInjection/PentatrionViteExtension.php @@ -116,17 +116,6 @@ private function entrypointsLookupFactory( return new Reference($id); } - /** - * Return absolute path to the build directory with final slash - * ex: "/path-to-your-project/public/build/". - */ - private function resolveBasePath(ContainerBuilder $container, $config): string - { - return $container->getParameter('kernel.project_dir') - .$container->getParameter('pentatrion_vite.public_directory') - .$config['base']; - } - private function tagRendererFactory( ContainerBuilder $container, string $configName, @@ -161,7 +150,7 @@ public static function prepareConfig(array $config): array ]; } - public static function preparePublicDirectory($publicDir) + public static function preparePublicDirectory(string $publicDir) { $publicDir = '/' !== substr($publicDir, 0, 1) ? '/'.$publicDir : $publicDir; $publicDir = rtrim($publicDir, '/'); diff --git a/src/EventListener/PreloadAssetsEventListener.php b/src/EventListener/PreloadAssetsEventListener.php index 729a18b..6096654 100644 --- a/src/EventListener/PreloadAssetsEventListener.php +++ b/src/EventListener/PreloadAssetsEventListener.php @@ -55,7 +55,7 @@ private function createLink(string $rel, string $href): Link return new Link($rel, $href); } - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [ // must run before AddLinkHeaderListener diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index f77273f..a13f415 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -61,8 +61,6 @@ services: - "%pentatrion_vite.proxy_origin%" Pentatrion\ViteBundle\Asset\ViteAssetVersionStrategy: - # tags: - # - { name: assets.package, package: vite } arguments: - "@pentatrion_vite.file_accessor" - "%pentatrion_vite.configs%" diff --git a/src/Twig/EntryFilesTwigExtension.php b/src/Twig/EntryFilesTwigExtension.php index bdb7126..6a73ff8 100644 --- a/src/Twig/EntryFilesTwigExtension.php +++ b/src/Twig/EntryFilesTwigExtension.php @@ -24,18 +24,18 @@ public function getFunctions(): array ]; } - public function getViteMode(string $buildName = null): ?string + public function getViteMode(?string $configName = null): ?string { - return $this->entrypointRenderer->getMode($buildName); + return $this->entrypointRenderer->getMode($configName); } - public function renderViteScriptTags(string $entryName, array $options = [], $buildName = null): string + public function renderViteScriptTags(string $entryName, array $options = [], ?string $configName = null): string { - return $this->entrypointRenderer->renderScripts($entryName, $options, $buildName); + return $this->entrypointRenderer->renderScripts($entryName, $options, $configName); } - public function renderViteLinkTags(string $entryName, array $options = [], $buildName = null): string + public function renderViteLinkTags(string $entryName, array $options = [], ?string $configName = null): string { - return $this->entrypointRenderer->renderLinks($entryName, $options, $buildName); + return $this->entrypointRenderer->renderLinks($entryName, $options, $configName); } } From 5e87d5e3419ca4f98b23173f9b1d1b3b2205c5d8 Mon Sep 17 00:00:00 2001 From: Hugues Tavernier Date: Fri, 3 Nov 2023 11:45:31 +0100 Subject: [PATCH 19/19] php-cs-fix --- src/Asset/EntrypointRenderer.php | 1 - src/Twig/EntryFilesTwigExtension.php | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Asset/EntrypointRenderer.php b/src/Asset/EntrypointRenderer.php index b80a8ae..d76be41 100644 --- a/src/Asset/EntrypointRenderer.php +++ b/src/Asset/EntrypointRenderer.php @@ -262,7 +262,6 @@ public function renderLinks( return $this->renderTags($tags, $isBuild, $toString); } - /** * @return string|array */ diff --git a/src/Twig/EntryFilesTwigExtension.php b/src/Twig/EntryFilesTwigExtension.php index 6a73ff8..a1f830b 100644 --- a/src/Twig/EntryFilesTwigExtension.php +++ b/src/Twig/EntryFilesTwigExtension.php @@ -24,17 +24,17 @@ public function getFunctions(): array ]; } - public function getViteMode(?string $configName = null): ?string + public function getViteMode(string $configName = null): ?string { return $this->entrypointRenderer->getMode($configName); } - public function renderViteScriptTags(string $entryName, array $options = [], ?string $configName = null): string + public function renderViteScriptTags(string $entryName, array $options = [], string $configName = null): string { return $this->entrypointRenderer->renderScripts($entryName, $options, $configName); } - public function renderViteLinkTags(string $entryName, array $options = [], ?string $configName = null): string + public function renderViteLinkTags(string $entryName, array $options = [], string $configName = null): string { return $this->entrypointRenderer->renderLinks($entryName, $options, $configName); }