From 1cc7362ef90525abf2fe632d5bd3c0d3b179b39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Wed, 25 Sep 2024 19:13:13 +0200 Subject: [PATCH 01/42] [TwigComponent] Cache component properties metadata --- src/TwigComponent/config/cache.php | 23 +++ .../CacheWarmer/TwigComponentCacheWarmer.php | 55 +++++++ src/TwigComponent/src/ComponentProperties.php | 148 ++++++++++++++++++ src/TwigComponent/src/ComponentRenderer.php | 63 +------- .../Compiler/TwigComponentPass.php | 3 + .../TwigComponentExtension.php | 29 +++- 6 files changed, 258 insertions(+), 63 deletions(-) create mode 100644 src/TwigComponent/config/cache.php create mode 100644 src/TwigComponent/src/CacheWarmer/TwigComponentCacheWarmer.php create mode 100644 src/TwigComponent/src/ComponentProperties.php diff --git a/src/TwigComponent/config/cache.php b/src/TwigComponent/config/cache.php new file mode 100644 index 00000000000..e8f62ee2027 --- /dev/null +++ b/src/TwigComponent/config/cache.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\TwigComponent\DependencyInjection\Loader\Configurator; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + +return static function (ContainerConfigurator $container): void { + $container->services() + ->set('cache.ux.twig_component') + ->parent('cache.system') + ->private() + ->tag('cache.pool') + ; +}; diff --git a/src/TwigComponent/src/CacheWarmer/TwigComponentCacheWarmer.php b/src/TwigComponent/src/CacheWarmer/TwigComponentCacheWarmer.php new file mode 100644 index 00000000000..fad5c74cade --- /dev/null +++ b/src/TwigComponent/src/CacheWarmer/TwigComponentCacheWarmer.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\TwigComponent\CacheWarmer; + +use Psr\Container\ContainerInterface; +use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; +use Symfony\UX\TwigComponent\ComponentProperties; + +/** + * Warm the TwigComponent metadata caches. + * + * @author Simon AndrΓ© + * + * @internal + */ +final class TwigComponentCacheWarmer implements CacheWarmerInterface, ServiceSubscriberInterface +{ + /** + * As this cache warmer is optional, dependencies should be lazy-loaded, that's why a container should be injected. + */ + public function __construct( + private readonly ContainerInterface $container, + ) { + } + + public static function getSubscribedServices(): array + { + return [ + 'ux.twig_component.component_properties' => ComponentProperties::class, + ]; + } + + public function warmUp(string $cacheDir, ?string $buildDir = null): array + { + $properties = $this->container->get('ux.twig_component.component_properties'); + $properties->warmup(); + + return []; + } + + public function isOptional(): bool + { + return true; + } +} diff --git a/src/TwigComponent/src/ComponentProperties.php b/src/TwigComponent/src/ComponentProperties.php new file mode 100644 index 00000000000..abb8c733a0e --- /dev/null +++ b/src/TwigComponent/src/ComponentProperties.php @@ -0,0 +1,148 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\TwigComponent; + +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate; + +/** + * @author Simon AndrΓ© + * + * @internal + */ +final class ComponentProperties +{ + private const CACHE_KEY = 'ux.twig_component.component_properties'; + + /** + * @var array, + * methods: array, + * }|null> + */ + private array $classMetadata; + + public function __construct( + private readonly PropertyAccessorInterface $propertyAccessor, + ?array $classMetadata = [], + private readonly ?AdapterInterface $cache = null, + ) { + $cacheItem = $this->cache?->getItem(self::CACHE_KEY); + + $this->classMetadata = $cacheItem?->isHit() ? [...$cacheItem->get(), ...$classMetadata] : $classMetadata; + } + + /** + * @return array + */ + public function getProperties(object $component, bool $publicProps = false): array + { + return iterator_to_array($this->extractProperties($component, $publicProps)); + } + + public function warmup(): void + { + if (!$this->cache) { + return; + } + + foreach ($this->classMetadata as $class => $metadata) { + if (null === $metadata) { + $this->classMetadata[$class] = $this->loadClassMetadata($class); + } + } + + $this->cache->save($this->cache->getItem(self::CACHE_KEY)->set($this->classMetadata)); + } + + /** + * @return \Generator + */ + private function extractProperties(object $component, bool $publicProps): \Generator + { + yield from $publicProps ? get_object_vars($component) : []; + + $metadata = $this->classMetadata[$component::class] ??= $this->loadClassMetadata($component::class); + + foreach ($metadata['properties'] as $propertyName => $property) { + $value = $property['getter'] ? $component->{$property['getter']}() : $this->propertyAccessor->getValue($component, $propertyName); + if ($property['destruct'] ?? false) { + yield from $value; + } else { + yield $property['name'] => $value; + } + } + + foreach ($metadata['methods'] as $methodName => $method) { + if ($method['destruct'] ?? false) { + yield from $component->{$methodName}(); + } else { + yield $method['name'] => $component->{$methodName}(); + } + } + } + + /** + * @param class-string $class + * + * @return array{ + * properties: array, + * methods: array, + * } + */ + private function loadClassMetadata(string $class): array + { + $refClass = new \ReflectionClass($class); + + $properties = []; + foreach ($refClass->getProperties() as $property) { + if (!$attributes = $property->getAttributes(ExposeInTemplate::class)) { + continue; + } + $attribute = $attributes[0]->newInstance(); + $properties[$property->name] = [ + 'name' => $attribute->name ?? $property->name, + 'getter' => $attribute->getter ? rtrim($attribute->getter, '()') : null, + ]; + if ($attribute->destruct) { + unset($properties[$property->name]['name']); + $properties[$property->name]['destruct'] = true; + } + } + + $methods = []; + foreach ($refClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { + if (!$attributes = $method->getAttributes(ExposeInTemplate::class)) { + continue; + } + if ($method->getNumberOfRequiredParameters()) { + throw new \LogicException(\sprintf('Cannot use "%s" on methods with required parameters (%s::%s).', ExposeInTemplate::class, $class, $method->name)); + } + $attribute = $attributes[0]->newInstance(); + $name = $attribute->name ?? (str_starts_with($method->name, 'get') ? lcfirst(substr($method->name, 3)) : $method->name); + $methods[$method->name] = $attribute->destruct ? ['destruct' => true] : ['name' => $name]; + } + + return [ + 'properties' => $properties, + 'methods' => $methods, + ]; + } +} diff --git a/src/TwigComponent/src/ComponentRenderer.php b/src/TwigComponent/src/ComponentRenderer.php index 3273ba5118f..fb6a01ffda6 100644 --- a/src/TwigComponent/src/ComponentRenderer.php +++ b/src/TwigComponent/src/ComponentRenderer.php @@ -11,9 +11,7 @@ namespace Symfony\UX\TwigComponent; -use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate; use Symfony\UX\TwigComponent\Event\PostRenderEvent; use Symfony\UX\TwigComponent\Event\PreCreateForRenderEvent; use Symfony\UX\TwigComponent\Event\PreRenderEvent; @@ -30,7 +28,7 @@ public function __construct( private Environment $twig, private EventDispatcherInterface $dispatcher, private ComponentFactory $factory, - private PropertyAccessorInterface $propertyAccessor, + private ComponentProperties $componentProperties, private ComponentStack $componentStack, ) { } @@ -107,9 +105,11 @@ private function preRender(MountedComponent $mounted, array $context = []): PreR { $component = $mounted->getComponent(); $metadata = $this->factory->metadataFor($mounted->getName()); - $isAnonymous = $mounted->getComponent() instanceof AnonymousComponent; - $classProps = $isAnonymous ? [] : iterator_to_array($this->exposedVariables($component, $metadata->isPublicPropsExposed())); + $classProps = []; + if (!$metadata->isAnonymous()) { + $classProps = $this->componentProperties->getProperties($component, $metadata->isPublicPropsExposed()); + } // expose public properties and properties marked with ExposeInTemplate attribute $props = [...$mounted->getInputProps(), ...$classProps]; @@ -137,57 +137,4 @@ private function preRender(MountedComponent $mounted, array $context = []): PreR return $event; } - - private function exposedVariables(object $component, bool $exposePublicProps): \Iterator - { - if ($exposePublicProps) { - yield from get_object_vars($component); - } - - $class = new \ReflectionClass($component); - - foreach ($class->getProperties() as $property) { - if (!$attribute = $property->getAttributes(ExposeInTemplate::class)[0] ?? null) { - continue; - } - - $attribute = $attribute->newInstance(); - - /** @var ExposeInTemplate $attribute */ - $value = $attribute->getter ? $component->{rtrim($attribute->getter, '()')}() : $this->propertyAccessor->getValue($component, $property->name); - - if ($attribute->destruct) { - foreach ($value as $key => $destructedValue) { - yield $key => $destructedValue; - } - } - - yield $attribute->name ?? $property->name => $value; - } - - foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { - if (!$attribute = $method->getAttributes(ExposeInTemplate::class)[0] ?? null) { - continue; - } - - $attribute = $attribute->newInstance(); - - /** @var ExposeInTemplate $attribute */ - $name = $attribute->name ?? (str_starts_with($method->name, 'get') ? lcfirst(substr($method->name, 3)) : $method->name); - - if ($method->getNumberOfRequiredParameters()) { - throw new \LogicException(\sprintf('Cannot use "%s" on methods with required parameters (%s::%s).', ExposeInTemplate::class, $component::class, $method->name)); - } - - if ($attribute->destruct) { - foreach ($component->{$method->name}() as $prop => $value) { - yield $prop => $value; - } - - return; - } - - yield $name => $component->{$method->name}(); - } - } } diff --git a/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php b/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php index 2a4ec1b0ba4..faf86afe925 100644 --- a/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php +++ b/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php @@ -80,6 +80,9 @@ public function process(ContainerBuilder $container): void $factoryDefinition->setArgument(4, $componentConfig); $factoryDefinition->setArgument(5, $componentClassMap); + $componentPropertiesDefinition = $container->findDefinition('ux.twig_component.component_properties'); + $componentPropertiesDefinition->setArgument(1, array_fill_keys(array_keys($componentClassMap), null)); + $debugCommandDefinition = $container->findDefinition('ux.twig_component.command.debug'); $debugCommandDefinition->setArgument(3, $componentClassMap); } diff --git a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php index 72cd6f261ab..0ee7230600a 100644 --- a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php +++ b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php @@ -21,14 +21,17 @@ use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\Reference; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; +use Symfony\UX\TwigComponent\CacheWarmer\TwigComponentCacheWarmer; use Symfony\UX\TwigComponent\Command\TwigComponentDebugCommand; use Symfony\UX\TwigComponent\ComponentFactory; +use Symfony\UX\TwigComponent\ComponentProperties; use Symfony\UX\TwigComponent\ComponentRenderer; use Symfony\UX\TwigComponent\ComponentRendererInterface; use Symfony\UX\TwigComponent\ComponentStack; @@ -84,21 +87,29 @@ static function (ChildDefinition $definition, AsTwigComponent $attribute) { $container->register('ux.twig_component.component_factory', ComponentFactory::class) ->setArguments([ new Reference('ux.twig_component.component_template_finder'), - class_exists(AbstractArgument::class) ? new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)) : null, + new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)), new Reference('property_accessor'), new Reference('event_dispatcher'), - class_exists(AbstractArgument::class) ? new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)) : [], + new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)), ]) ; $container->register('ux.twig_component.component_stack', ComponentStack::class); + $container->register('ux.twig_component.component_properties', ComponentProperties::class) + ->setArguments([ + new Reference('property_accessor'), + new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)), + new Reference('cache.ux.twig_component', ContainerInterface::IGNORE_ON_INVALID_REFERENCE), + ]) + ; + $container->register('ux.twig_component.component_renderer', ComponentRenderer::class) ->setArguments([ new Reference('twig'), new Reference('event_dispatcher'), new Reference('ux.twig_component.component_factory'), - new Reference('property_accessor'), + new Reference('ux.twig_component.component_properties'), new Reference('ux.twig_component.component_stack'), ]) ; @@ -107,7 +118,7 @@ class_exists(AbstractArgument::class) ? new AbstractArgument(\sprintf('Added in ->addTag('twig.extension') ; - $container->register('.ux.twig_component.twig.component_runtime', ComponentRuntime::class) + $container->register('ux.twig_component.twig.component_runtime', ComponentRuntime::class) ->setArguments([ new Reference('ux.twig_component.component_renderer'), new ServiceLocatorArgument(new TaggedIteratorArgument('ux.twig_component.twig_renderer', indexAttribute: 'key', needsIndexes: true)), @@ -126,7 +137,7 @@ class_exists(AbstractArgument::class) ? new AbstractArgument(\sprintf('Added in new Parameter('twig.default_path'), new Reference('ux.twig_component.component_factory'), new Reference('twig'), - class_exists(AbstractArgument::class) ? new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)) : [], + new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)), $config['anonymous_template_directory'], ]) ->addTag('console.command') @@ -138,6 +149,14 @@ class_exists(AbstractArgument::class) ? new AbstractArgument(\sprintf('Added in if ($container->getParameter('kernel.debug') && $config['profiler']) { $loader->load('debug.php'); } + + $loader->load('cache.php'); + + $container->register('ux.twig_component.cache_warmer', TwigComponentCacheWarmer::class) + ->setArguments([new Reference(\Psr\Container\ContainerInterface::class)]) + ->addTag('kernel.cache_warmer') + ->addTag('container.service_subscriber', ['id' => 'ux.twig_component.component_properties']) + ; } public function getConfigTreeBuilder(): TreeBuilder From 9956b576df4e9ada903c4f71d880427a9612c2f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Fri, 1 Nov 2024 19:48:40 +0100 Subject: [PATCH 02/42] [UX] Update the issue template - Fix labels for Bug and RFC - Add guidelines comment for bug report --- .github/ISSUE_TEMPLATE/1-bug_report.md | 26 ++++++++++++++++++++- .github/ISSUE_TEMPLATE/2-feature_request.md | 2 +- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/1-bug_report.md b/.github/ISSUE_TEMPLATE/1-bug_report.md index 03391625afb..36713b354f1 100644 --- a/.github/ISSUE_TEMPLATE/1-bug_report.md +++ b/.github/ISSUE_TEMPLATE/1-bug_report.md @@ -2,7 +2,31 @@ name: '🐞 Bug Report' about: Report a bug in existing features title: '' -labels: 'bug' +labels: ['Bug'] assignees: '' --- + + + + + diff --git a/.github/ISSUE_TEMPLATE/2-feature_request.md b/.github/ISSUE_TEMPLATE/2-feature_request.md index a6e92dc1a1a..ca32d4ee663 100644 --- a/.github/ISSUE_TEMPLATE/2-feature_request.md +++ b/.github/ISSUE_TEMPLATE/2-feature_request.md @@ -2,7 +2,7 @@ name: 'πŸš€ Feature Request' about: Suggest ideas for new features or enhancements title: '' -labels: 'RFC' +labels: ['RFC'] assignees: '' --- From f7ae685d68783f8b76606cb7b4e31e1915aeb157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sat, 2 Nov 2024 03:58:40 +0100 Subject: [PATCH 03/42] [Site] Test Symfony 7.2 beta --- ux.symfony.com/.symfony.local.yaml | 3 + ux.symfony.com/composer.json | 68 +- ux.symfony.com/composer.lock | 796 +++++++++--------- .../config/packages/symfonycasts_sass.yaml | 5 + 4 files changed, 447 insertions(+), 425 deletions(-) create mode 100644 ux.symfony.com/config/packages/symfonycasts_sass.yaml diff --git a/ux.symfony.com/.symfony.local.yaml b/ux.symfony.com/.symfony.local.yaml index cc6d3fe35a0..4257e69ba26 100644 --- a/ux.symfony.com/.symfony.local.yaml +++ b/ux.symfony.com/.symfony.local.yaml @@ -2,3 +2,6 @@ workers: docker_compose: ~ sass: cmd: ['symfony', 'console', 'sass:build', '--watch'] + +http: + use_gzip: true diff --git a/ux.symfony.com/composer.json b/ux.symfony.com/composer.json index 1931679b8b8..bd7335cafca 100644 --- a/ux.symfony.com/composer.json +++ b/ux.symfony.com/composer.json @@ -7,31 +7,31 @@ "php": ">=8.3", "ext-ctype": "*", "ext-iconv": "*", - "composer/semver": "^3.4", + "composer/semver": "^3.4.3", "doctrine/doctrine-bundle": "^2.13", "doctrine/doctrine-migrations-bundle": "^3.3.1", - "doctrine/orm": "^2.19.7", + "doctrine/orm": "^2.20.0", "intervention/image": "^2.7.2", "kornrunner/blurhash": "^1.2.2", - "league/commonmark": "^2.5", - "symfony/asset": "7.1.*", - "symfony/asset-mapper": "7.1.*", - "symfony/console": "7.1.*", - "symfony/dotenv": "7.1.*", - "symfony/expression-language": "7.1.*", - "symfony/flex": "^2.4", - "symfony/form": "7.1.*", - "symfony/framework-bundle": "7.1.*", - "symfony/http-client": "7.1.*", + "league/commonmark": "^2.5.3", + "symfony/asset": "7.2.*", + "symfony/asset-mapper": "7.2.*", + "symfony/console": "7.2.*", + "symfony/dotenv": "7.2.*", + "symfony/expression-language": "7.2.*", + "symfony/flex": "^2.4.7", + "symfony/form": "7.2.*", + "symfony/framework-bundle": "7.2.*", + "symfony/http-client": "7.2.*", "symfony/mercure-bundle": "^0.3.9", - "symfony/monolog-bundle": "^3.11", - "symfony/notifier": "7.1.*", - "symfony/runtime": "7.1.*", - "symfony/serializer": "7.1.*", + "symfony/monolog-bundle": "^3.10", + "symfony/notifier": "7.2.*", + "symfony/runtime": "7.2.*", + "symfony/serializer": "7.2.*", "symfony/stimulus-bundle": "2.x-dev", - "symfony/translation": "7.1.*", - "symfony/twig-bundle": "7.1.*", - "symfony/uid": "7.1.*", + "symfony/translation": "7.2.*", + "symfony/twig-bundle": "7.2.*", + "symfony/uid": "7.2.*", "symfony/ux-autocomplete": "2.x-dev", "symfony/ux-chartjs": "2.x-dev", "symfony/ux-cropperjs": "2.x-dev", @@ -51,12 +51,12 @@ "symfony/ux-twig-component": "2.x-dev", "symfony/ux-typed": "2.x-dev", "symfony/ux-vue": "2.x-dev", - "symfony/validator": "7.1.*", - "symfony/yaml": "7.1.*", + "symfony/validator": "7.2.*", + "symfony/yaml": "7.2.*", "symfonycasts/dynamic-forms": "^0.1.2", - "symfonycasts/sass-bundle": "^0.6.0", - "tempest/highlight": "^2.10.3", - "twbs/bootstrap": "^5.3", + "symfonycasts/sass-bundle": "0.8.*", + "tempest/highlight": "^2.10.6", + "twbs/bootstrap": "^5.3.3", "twig/extra-bundle": "^3.13", "twig/html-extra": "^3.13", "twig/intl-extra": "^3.13", @@ -65,17 +65,17 @@ "twig/twig": "^3.14" }, "require-dev": { - "phpunit/phpunit": "^9.6.9", - "symfony/browser-kit": "7.1.*", - "symfony/css-selector": "7.1.*", - "symfony/debug-bundle": "7.1.*", - "symfony/maker-bundle": "^1.60", - "symfony/phpunit-bridge": "7.1.*", - "symfony/stopwatch": "7.1.*", - "symfony/web-profiler-bundle": "7.1.*", + "phpunit/phpunit": "^9.6.21", + "symfony/browser-kit": "7.2.*", + "symfony/css-selector": "7.2.*", + "symfony/debug-bundle": "7.2.*", + "symfony/maker-bundle": "^1.61", + "symfony/phpunit-bridge": "7.2.*", + "symfony/stopwatch": "7.2.*", + "symfony/web-profiler-bundle": "7.2.*", "vincentlanglet/twig-cs-fixer": "3.1.*", "zenstruck/browser": "^1.9", - "zenstruck/foundry": "2.0.*" + "zenstruck/foundry": "2.2.*" }, "replace": { "symfony/polyfill-ctype": "*", @@ -119,7 +119,7 @@ "symfony": { "allow-contrib": false, "docker": true, - "require": "7.1.*" + "require": "7.2.*" } }, "scripts": { diff --git a/ux.symfony.com/composer.lock b/ux.symfony.com/composer.lock index 43e4ea9d11d..64824239bd2 100644 --- a/ux.symfony.com/composer.lock +++ b/ux.symfony.com/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": "a1a1ef4f3aba41044cc0f8c7a74f73f7", + "content-hash": "f9bf689e0e76abae07cd63aa31447eea", "packages": [ { "name": "composer/semver", @@ -1341,16 +1341,16 @@ }, { "name": "doctrine/persistence", - "version": "3.3.3", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "b337726451f5d530df338fc7f68dee8781b49779" + "reference": "0ea965320cec355dba75031c1b23d4c78362e3ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/b337726451f5d530df338fc7f68dee8781b49779", - "reference": "b337726451f5d530df338fc7f68dee8781b49779", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/0ea965320cec355dba75031c1b23d4c78362e3ff", + "reference": "0ea965320cec355dba75031c1b23d4c78362e3ff", "shasum": "" }, "require": { @@ -1364,12 +1364,11 @@ "require-dev": { "doctrine/coding-standard": "^12", "doctrine/common": "^3.0", - "phpstan/phpstan": "1.11.1", + "phpstan/phpstan": "1.12.7", "phpstan/phpstan-phpunit": "^1", "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6.0", - "vimeo/psalm": "4.30.0 || 5.24.0" + "phpunit/phpunit": "^8.5.38 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0" }, "type": "library", "autoload": { @@ -1418,7 +1417,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.3.3" + "source": "https://github.com/doctrine/persistence/tree/3.4.0" }, "funding": [ { @@ -1434,7 +1433,7 @@ "type": "tidelift" } ], - "time": "2024-06-20T10:14:30+00:00" + "time": "2024-10-30T19:48:12+00:00" }, { "name": "doctrine/sql-formatter", @@ -2710,16 +2709,16 @@ }, { "name": "symfony/asset", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "8970de4a0cedd34e097c0f5c502a614780b9ca43" + "reference": "cb926cd59fefa1f9b4900b3695f0f846797ba5c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/8970de4a0cedd34e097c0f5c502a614780b9ca43", - "reference": "8970de4a0cedd34e097c0f5c502a614780b9ca43", + "url": "https://api.github.com/repos/symfony/asset/zipball/cb926cd59fefa1f9b4900b3695f0f846797ba5c0", + "reference": "cb926cd59fefa1f9b4900b3695f0f846797ba5c0", "shasum": "" }, "require": { @@ -2759,7 +2758,7 @@ "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/v7.1.1" + "source": "https://github.com/symfony/asset/tree/v7.2.0-BETA1" }, "funding": [ { @@ -2775,20 +2774,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/asset-mapper", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/asset-mapper.git", - "reference": "e3ae56f965f1fe503db1f604756a44d40e6dea16" + "reference": "984b58a711b8e8ad5c494b4fa827929b59b3916f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/e3ae56f965f1fe503db1f604756a44d40e6dea16", - "reference": "e3ae56f965f1fe503db1f604756a44d40e6dea16", + "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/984b58a711b8e8ad5c494b4fa827929b59b3916f", + "reference": "984b58a711b8e8ad5c494b4fa827929b59b3916f", "shasum": "" }, "require": { @@ -2838,7 +2837,7 @@ "description": "Maps directories of assets & makes them available in a public directory with versioned filenames.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset-mapper/tree/v7.1.5" + "source": "https://github.com/symfony/asset-mapper/tree/v7.2.0-BETA1" }, "funding": [ { @@ -2854,20 +2853,20 @@ "type": "tidelift" } ], - "time": "2024-09-19T08:57:32+00:00" + "time": "2024-09-27T08:35:32+00:00" }, { "name": "symfony/cache", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "86e5296b10e4dec8c8441056ca606aedb8a3be0a" + "reference": "1354995a9e758e7141a90ed99248a0e21bee701d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/86e5296b10e4dec8c8441056ca606aedb8a3be0a", - "reference": "86e5296b10e4dec8c8441056ca606aedb8a3be0a", + "url": "https://api.github.com/repos/symfony/cache/zipball/1354995a9e758e7141a90ed99248a0e21bee701d", + "reference": "1354995a9e758e7141a90ed99248a0e21bee701d", "shasum": "" }, "require": { @@ -2895,6 +2894,7 @@ "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", "symfony/dependency-injection": "^6.4|^7.0", "symfony/filesystem": "^6.4|^7.0", @@ -2935,7 +2935,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.1.5" + "source": "https://github.com/symfony/cache/tree/v7.2.0-BETA1" }, "funding": [ { @@ -2951,7 +2951,7 @@ "type": "tidelift" } ], - "time": "2024-09-17T09:16:35+00:00" + "time": "2024-10-25T15:40:01+00:00" }, { "name": "symfony/cache-contracts", @@ -3031,16 +3031,16 @@ }, { "name": "symfony/config", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "2210fc99fa42a259eb6c89d1f724ce0c4d62d5d2" + "reference": "75cfe49f73d6d43110690e55fb212d697ee598d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/2210fc99fa42a259eb6c89d1f724ce0c4d62d5d2", - "reference": "2210fc99fa42a259eb6c89d1f724ce0c4d62d5d2", + "url": "https://api.github.com/repos/symfony/config/zipball/75cfe49f73d6d43110690e55fb212d697ee598d9", + "reference": "75cfe49f73d6d43110690e55fb212d697ee598d9", "shasum": "" }, "require": { @@ -3086,7 +3086,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/v7.1.1" + "source": "https://github.com/symfony/config/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3102,20 +3102,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/console", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee" + "reference": "de74db6d7c9f4ecabf7b4a1a20655e021b034001" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee", - "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee", + "url": "https://api.github.com/repos/symfony/console/zipball/de74db6d7c9f4ecabf7b4a1a20655e021b034001", + "reference": "de74db6d7c9f4ecabf7b4a1a20655e021b034001", "shasum": "" }, "require": { @@ -3179,7 +3179,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.5" + "source": "https://github.com/symfony/console/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3195,20 +3195,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "38465f925ec4e0707b090e9147c65869837d639d" + "reference": "6d5c6520d1984bc67af228dd6519e03e58661d7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/38465f925ec4e0707b090e9147c65869837d639d", - "reference": "38465f925ec4e0707b090e9147c65869837d639d", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/6d5c6520d1984bc67af228dd6519e03e58661d7f", + "reference": "6d5c6520d1984bc67af228dd6519e03e58661d7f", "shasum": "" }, "require": { @@ -3259,7 +3259,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/v7.1.5" + "source": "https://github.com/symfony/dependency-injection/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3275,7 +3275,7 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3346,16 +3346,16 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "2568d0adaa5b0018b07beaa90363b880a43cc957" + "reference": "653ab90f3b2c7fcd3a37b29c23552ab7680f54d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/2568d0adaa5b0018b07beaa90363b880a43cc957", - "reference": "2568d0adaa5b0018b07beaa90363b880a43cc957", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/653ab90f3b2c7fcd3a37b29c23552ab7680f54d2", + "reference": "653ab90f3b2c7fcd3a37b29c23552ab7680f54d2", "shasum": "" }, "require": { @@ -3368,6 +3368,7 @@ "symfony/service-contracts": "^2.5|^3" }, "conflict": { + "doctrine/collections": "<1.8", "doctrine/dbal": "<3.6", "doctrine/lexer": "<1.1", "doctrine/orm": "<2.15", @@ -3384,7 +3385,7 @@ "symfony/validator": "<6.4" }, "require-dev": { - "doctrine/collections": "^1.0|^2.0", + "doctrine/collections": "^1.8|^2.0", "doctrine/data-fixtures": "^1.1", "doctrine/dbal": "^3.6|^4", "doctrine/orm": "^2.15|^3", @@ -3434,7 +3435,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.1.5" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3450,20 +3451,20 @@ "type": "tidelift" } ], - "time": "2024-09-08T12:32:26+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfony/dotenv", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "6d966200b399fa59759286f3fc7c919f0677c449" + "reference": "07b2c58767aadc8ed96b26fadc513a0d00ccd084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/6d966200b399fa59759286f3fc7c919f0677c449", - "reference": "6d966200b399fa59759286f3fc7c919f0677c449", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/07b2c58767aadc8ed96b26fadc513a0d00ccd084", + "reference": "07b2c58767aadc8ed96b26fadc513a0d00ccd084", "shasum": "" }, "require": { @@ -3508,7 +3509,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v7.1.5" + "source": "https://github.com/symfony/dotenv/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3524,20 +3525,20 @@ "type": "tidelift" } ], - "time": "2024-09-17T09:16:35+00:00" + "time": "2024-09-28T12:51:41+00:00" }, { "name": "symfony/error-handler", - "version": "v7.1.3", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "432bb369952795c61ca1def65e078c4a80dad13c" + "reference": "ad57ca04868ca877e7919c56d20bdfa8024b54d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/432bb369952795c61ca1def65e078c4a80dad13c", - "reference": "432bb369952795c61ca1def65e078c4a80dad13c", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/ad57ca04868ca877e7919c56d20bdfa8024b54d6", + "reference": "ad57ca04868ca877e7919c56d20bdfa8024b54d6", "shasum": "" }, "require": { @@ -3583,7 +3584,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/v7.1.3" + "source": "https://github.com/symfony/error-handler/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3599,20 +3600,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T13:02:51+00:00" + "time": "2024-10-14T08:54:27+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7" + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7", - "reference": "9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", "shasum": "" }, "require": { @@ -3663,7 +3664,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/v7.1.1" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3679,7 +3680,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -3759,16 +3760,16 @@ }, { "name": "symfony/expression-language", - "version": "v7.1.4", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "b9e4bc6685d513c10235145ed1042a6081635806" + "reference": "26f4884a455e755e630a5fc372df124a3578da2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/b9e4bc6685d513c10235145ed1042a6081635806", - "reference": "b9e4bc6685d513c10235145ed1042a6081635806", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/26f4884a455e755e630a5fc372df124a3578da2e", + "reference": "26f4884a455e755e630a5fc372df124a3578da2e", "shasum": "" }, "require": { @@ -3803,7 +3804,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v7.1.4" + "source": "https://github.com/symfony/expression-language/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3819,20 +3820,20 @@ "type": "tidelift" } ], - "time": "2024-08-12T09:59:40+00:00" + "time": "2024-10-15T11:52:45+00:00" }, { "name": "symfony/filesystem", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a" + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a", - "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", "shasum": "" }, "require": { @@ -3869,7 +3870,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.1.5" + "source": "https://github.com/symfony/filesystem/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3885,20 +3886,20 @@ "type": "tidelift" } ], - "time": "2024-09-17T09:16:35+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/finder", - "version": "v7.1.4", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d95bbf319f7d052082fb7af147e0f835a695e823" + "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823", - "reference": "d95bbf319f7d052082fb7af147e0f835a695e823", + "url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49", + "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49", "shasum": "" }, "require": { @@ -3933,7 +3934,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.1.4" + "source": "https://github.com/symfony/finder/tree/v7.2.0-BETA1" }, "funding": [ { @@ -3949,7 +3950,7 @@ "type": "tidelift" } ], - "time": "2024-08-13T14:28:19+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfony/flex", @@ -4021,16 +4022,16 @@ }, { "name": "symfony/form", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "6b8b53ad6d42f14b158c896163b96ff260d78222" + "reference": "73c00ef4ced12b43647a37c184f05650c636a539" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/6b8b53ad6d42f14b158c896163b96ff260d78222", - "reference": "6b8b53ad6d42f14b158c896163b96ff260d78222", + "url": "https://api.github.com/repos/symfony/form/zipball/73c00ef4ced12b43647a37c184f05650c636a539", + "reference": "73c00ef4ced12b43647a37c184f05650c636a539", "shasum": "" }, "require": { @@ -4098,7 +4099,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v7.1.5" + "source": "https://github.com/symfony/form/tree/v7.2.0-BETA1" }, "funding": [ { @@ -4114,20 +4115,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfony/framework-bundle", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "8a792de86230c13a9de7750c0c8b23cc083183d4" + "reference": "8a7df876a98d15c8b9f01b10397a76d5de548324" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/8a792de86230c13a9de7750c0c8b23cc083183d4", - "reference": "8a792de86230c13a9de7750c0c8b23cc083183d4", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/8a7df876a98d15c8b9f01b10397a76d5de548324", + "reference": "8a7df876a98d15c8b9f01b10397a76d5de548324", "shasum": "" }, "require": { @@ -4136,14 +4137,14 @@ "php": ">=8.2", "symfony/cache": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^7.1.5", + "symfony/dependency-injection": "^7.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.4|^7.0", "symfony/event-dispatcher": "^6.4|^7.0", "symfony/filesystem": "^7.1", "symfony/finder": "^6.4|^7.0", "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", + "symfony/http-kernel": "^7.2", "symfony/polyfill-mbstring": "~1.0", "symfony/routing": "^6.4|^7.0" }, @@ -4165,16 +4166,18 @@ "symfony/mime": "<6.4", "symfony/property-access": "<6.4", "symfony/property-info": "<6.4", + "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", "symfony/security-core": "<6.4", - "symfony/security-csrf": "<6.4", - "symfony/serializer": "<6.4", + "symfony/security-csrf": "<7.2", + "symfony/serializer": "<7.1", "symfony/stopwatch": "<6.4", "symfony/translation": "<6.4", "symfony/twig-bridge": "<6.4", "symfony/twig-bundle": "<6.4", "symfony/validator": "<6.4", "symfony/web-profiler-bundle": "<6.4", + "symfony/webhook": "<7.2", "symfony/workflow": "<6.4" }, "require-dev": { @@ -4206,7 +4209,7 @@ "symfony/scheduler": "^6.4.4|^7.0.4", "symfony/security-bundle": "^6.4|^7.0", "symfony/semaphore": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/serializer": "^7.1", "symfony/stopwatch": "^6.4|^7.0", "symfony/string": "^6.4|^7.0", "symfony/translation": "^6.4|^7.0", @@ -4215,9 +4218,10 @@ "symfony/uid": "^6.4|^7.0", "symfony/validator": "^6.4|^7.0", "symfony/web-link": "^6.4|^7.0", + "symfony/webhook": "^7.2", "symfony/workflow": "^6.4|^7.0", "symfony/yaml": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, "type": "symfony-bundle", "autoload": { @@ -4245,7 +4249,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/v7.1.5" + "source": "https://github.com/symfony/framework-bundle/tree/v7.2.0-BETA1" }, "funding": [ { @@ -4261,20 +4265,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T13:35:23+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/http-client", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "abca35865118edf35a23f2f24978a1784c831cb4" + "reference": "dee07290e432b1dde37dbb4ea1d67663f3cce0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/abca35865118edf35a23f2f24978a1784c831cb4", - "reference": "abca35865118edf35a23f2f24978a1784c831cb4", + "url": "https://api.github.com/repos/symfony/http-client/zipball/dee07290e432b1dde37dbb4ea1d67663f3cce0bc", + "reference": "dee07290e432b1dde37dbb4ea1d67663f3cce0bc", "shasum": "" }, "require": { @@ -4285,6 +4289,7 @@ "symfony/service-contracts": "^2.5|^3" }, "conflict": { + "amphp/amp": "<2.5", "php-http/discovery": "<1.15", "symfony/http-foundation": "<6.4" }, @@ -4295,14 +4300,14 @@ "symfony/http-client-implementation": "3.0" }, "require-dev": { - "amphp/amp": "^2.5", - "amphp/http-client": "^4.2.1", - "amphp/http-tunnel": "^1.0", + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", "amphp/socket": "^1.1", "guzzlehttp/promises": "^1.4|^2.0", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", "symfony/dependency-injection": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", "symfony/messenger": "^6.4|^7.0", @@ -4339,7 +4344,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.1.5" + "source": "https://github.com/symfony/http-client/tree/v7.2.0-BETA1" }, "funding": [ { @@ -4355,7 +4360,7 @@ "type": "tidelift" } ], - "time": "2024-09-20T13:35:23+00:00" + "time": "2024-10-22T19:26:41+00:00" }, { "name": "symfony/http-client-contracts", @@ -4437,20 +4442,21 @@ }, { "name": "symfony/http-foundation", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "e30ef73b1e44eea7eb37ba69600a354e553f694b" + "reference": "735b8519a8bcbf603d3af0430fb1be5c8822af13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e30ef73b1e44eea7eb37ba69600a354e553f694b", - "reference": "e30ef73b1e44eea7eb37ba69600a354e553f694b", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/735b8519a8bcbf603d3af0430fb1be5c8822af13", + "reference": "735b8519a8bcbf603d3af0430fb1be5c8822af13", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-mbstring": "~1.1", "symfony/polyfill-php83": "^1.27" }, @@ -4494,7 +4500,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.1.5" + "source": "https://github.com/symfony/http-foundation/tree/v7.2.0-BETA1" }, "funding": [ { @@ -4510,20 +4516,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "44204d96150a9df1fc57601ec933d23fefc2d65b" + "reference": "1d5619199df507f9f03584ae9141924cc148050e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/44204d96150a9df1fc57601ec933d23fefc2d65b", - "reference": "44204d96150a9df1fc57601ec933d23fefc2d65b", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1d5619199df507f9f03584ae9141924cc148050e", + "reference": "1d5619199df507f9f03584ae9141924cc148050e", "shasum": "" }, "require": { @@ -4552,7 +4558,7 @@ "symfony/twig-bridge": "<6.4", "symfony/validator": "<6.4", "symfony/var-dumper": "<6.4", - "twig/twig": "<3.0.4" + "twig/twig": "<3.12" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" @@ -4580,7 +4586,7 @@ "symfony/validator": "^6.4|^7.0", "symfony/var-dumper": "^6.4|^7.0", "symfony/var-exporter": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, "type": "library", "autoload": { @@ -4608,7 +4614,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/v7.1.5" + "source": "https://github.com/symfony/http-kernel/tree/v7.2.0-BETA1" }, "funding": [ { @@ -4624,20 +4630,20 @@ "type": "tidelift" } ], - "time": "2024-09-21T06:09:21+00:00" + "time": "2024-10-27T15:21:58+00:00" }, { "name": "symfony/intl", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "a0ba7a400e4c915500762c998355bea219a32d6b" + "reference": "e0c8d9c19b3a52f2d379319fd16298568ce9573d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/a0ba7a400e4c915500762c998355bea219a32d6b", - "reference": "a0ba7a400e4c915500762c998355bea219a32d6b", + "url": "https://api.github.com/repos/symfony/intl/zipball/e0c8d9c19b3a52f2d379319fd16298568ce9573d", + "reference": "e0c8d9c19b3a52f2d379319fd16298568ce9573d", "shasum": "" }, "require": { @@ -4694,7 +4700,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v7.1.5" + "source": "https://github.com/symfony/intl/tree/v7.2.0-BETA1" }, "funding": [ { @@ -4710,7 +4716,7 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-08T07:22:49+00:00" }, { "name": "symfony/mercure", @@ -4881,22 +4887,22 @@ }, { "name": "symfony/mercure-notifier", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/mercure-notifier.git", - "reference": "8580a527487ac171445cc46a7dc4ef878333c2c4" + "reference": "790a1d45ec6efe644aa7a136ccedadc2023f6985" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mercure-notifier/zipball/8580a527487ac171445cc46a7dc4ef878333c2c4", - "reference": "8580a527487ac171445cc46a7dc4ef878333c2c4", + "url": "https://api.github.com/repos/symfony/mercure-notifier/zipball/790a1d45ec6efe644aa7a136ccedadc2023f6985", + "reference": "790a1d45ec6efe644aa7a136ccedadc2023f6985", "shasum": "" }, "require": { "php": ">=8.2", "symfony/mercure": "^0.5.2|^0.6", - "symfony/notifier": "^6.4|^7.0", + "symfony/notifier": "^7.2", "symfony/service-contracts": "^2.5|^3" }, "type": "symfony-notifier-bridge", @@ -4929,7 +4935,7 @@ "notifier" ], "support": { - "source": "https://github.com/symfony/mercure-notifier/tree/v7.1.1" + "source": "https://github.com/symfony/mercure-notifier/tree/v7.2.0-BETA1" }, "funding": [ { @@ -4945,20 +4951,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-27T08:38:14+00:00" }, { "name": "symfony/mime", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "711d2e167e8ce65b05aea6b258c449671cdd38ff" + "reference": "e57faea55d255c31b0899f0130c7d9da65fa2ec7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/711d2e167e8ce65b05aea6b258c449671cdd38ff", - "reference": "711d2e167e8ce65b05aea6b258c449671cdd38ff", + "url": "https://api.github.com/repos/symfony/mime/zipball/e57faea55d255c31b0899f0130c7d9da65fa2ec7", + "reference": "e57faea55d255c31b0899f0130c7d9da65fa2ec7", "shasum": "" }, "require": { @@ -5013,7 +5019,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.1.5" + "source": "https://github.com/symfony/mime/tree/v7.2.0-BETA1" }, "funding": [ { @@ -5029,20 +5035,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "727be11ae17bb1c5a7f600753b9a1bf0cc0ec3b8" + "reference": "bbae784f0456c5a87c89d7c1a3fcc9cbee976c1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/727be11ae17bb1c5a7f600753b9a1bf0cc0ec3b8", - "reference": "727be11ae17bb1c5a7f600753b9a1bf0cc0ec3b8", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/bbae784f0456c5a87c89d7c1a3fcc9cbee976c1d", + "reference": "bbae784f0456c5a87c89d7c1a3fcc9cbee976c1d", "shasum": "" }, "require": { @@ -5091,7 +5097,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v7.1.1" + "source": "https://github.com/symfony/monolog-bridge/tree/v7.2.0-BETA1" }, "funding": [ { @@ -5107,20 +5113,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-10-14T18:16:08+00:00" }, { "name": "symfony/monolog-bundle", - "version": "dev-master", + "version": "v3.10.0", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "ed0e4a287282971d110fd8c99d9ac391559a43ce" + "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/ed0e4a287282971d110fd8c99d9ac391559a43ce", - "reference": "ed0e4a287282971d110fd8c99d9ac391559a43ce", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", + "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", "shasum": "" }, "require": { @@ -5133,10 +5139,9 @@ }, "require-dev": { "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/phpunit-bridge": "^7.1", + "symfony/phpunit-bridge": "^6.3 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, - "default-branch": true, "type": "symfony-bundle", "extra": { "branch-alias": { @@ -5173,7 +5178,7 @@ ], "support": { "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/master" + "source": "https://github.com/symfony/monolog-bundle/tree/v3.10.0" }, "funding": [ { @@ -5189,20 +5194,20 @@ "type": "tidelift" } ], - "time": "2024-08-06T10:03:39+00:00" + "time": "2023-11-06T17:08:13+00:00" }, { "name": "symfony/notifier", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/notifier.git", - "reference": "843946b0b1018ddc714b467f223607c71f9f6c8f" + "reference": "1a2a1639d102add41aa6896ff683cc05e3d52197" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/notifier/zipball/843946b0b1018ddc714b467f223607c71f9f6c8f", - "reference": "843946b0b1018ddc714b467f223607c71f9f6c8f", + "url": "https://api.github.com/repos/symfony/notifier/zipball/1a2a1639d102add41aa6896ff683cc05e3d52197", + "reference": "1a2a1639d102add41aa6896ff683cc05e3d52197", "shasum": "" }, "require": { @@ -5251,7 +5256,7 @@ "notifier" ], "support": { - "source": "https://github.com/symfony/notifier/tree/v7.1.5" + "source": "https://github.com/symfony/notifier/tree/v7.2.0-BETA1" }, "funding": [ { @@ -5267,20 +5272,20 @@ "type": "tidelift" } ], - "time": "2024-09-08T12:32:26+00:00" + "time": "2024-10-17T20:56:22+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55" + "reference": "4f69e6b9745493ea38e5ffdc937e41e7145aa04c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4f69e6b9745493ea38e5ffdc937e41e7145aa04c", + "reference": "4f69e6b9745493ea38e5ffdc937e41e7145aa04c", "shasum": "" }, "require": { @@ -5318,7 +5323,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.1.1" + "source": "https://github.com/symfony/options-resolver/tree/v7.2.0-BETA1" }, "funding": [ { @@ -5334,7 +5339,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -5823,16 +5828,16 @@ }, { "name": "symfony/process", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "5c03ee6369281177f07f7c68252a280beccba847" + "reference": "2ad775b9f17c8c9c1fe457750ce191e0f7c1fbff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847", - "reference": "5c03ee6369281177f07f7c68252a280beccba847", + "url": "https://api.github.com/repos/symfony/process/zipball/2ad775b9f17c8c9c1fe457750ce191e0f7c1fbff", + "reference": "2ad775b9f17c8c9c1fe457750ce191e0f7c1fbff", "shasum": "" }, "require": { @@ -5864,7 +5869,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.5" + "source": "https://github.com/symfony/process/tree/v7.2.0-BETA1" }, "funding": [ { @@ -5880,20 +5885,20 @@ "type": "tidelift" } ], - "time": "2024-09-19T21:48:23+00:00" + "time": "2024-09-26T08:57:56+00:00" }, { "name": "symfony/property-access", - "version": "v7.1.4", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "6c709f97103355016e5782d0622437ae381012ad" + "reference": "3ae42efba01e45aaedecf5c93c8d6a3ab3a82276" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/6c709f97103355016e5782d0622437ae381012ad", - "reference": "6c709f97103355016e5782d0622437ae381012ad", + "url": "https://api.github.com/repos/symfony/property-access/zipball/3ae42efba01e45aaedecf5c93c8d6a3ab3a82276", + "reference": "3ae42efba01e45aaedecf5c93c8d6a3ab3a82276", "shasum": "" }, "require": { @@ -5940,7 +5945,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v7.1.4" + "source": "https://github.com/symfony/property-access/tree/v7.2.0-BETA1" }, "funding": [ { @@ -5956,20 +5961,20 @@ "type": "tidelift" } ], - "time": "2024-08-30T16:12:47+00:00" + "time": "2024-09-26T12:28:35+00:00" }, { "name": "symfony/property-info", - "version": "v7.1.3", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "88a279df2db5b7919cac6f35d6a5d1d7147e6a9b" + "reference": "f8c1e96378984c4ae72caa2e304728999d2fd580" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/88a279df2db5b7919cac6f35d6a5d1d7147e6a9b", - "reference": "88a279df2db5b7919cac6f35d6a5d1d7147e6a9b", + "url": "https://api.github.com/repos/symfony/property-info/zipball/f8c1e96378984c4ae72caa2e304728999d2fd580", + "reference": "f8c1e96378984c4ae72caa2e304728999d2fd580", "shasum": "" }, "require": { @@ -6024,7 +6029,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v7.1.3" + "source": "https://github.com/symfony/property-info/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6040,20 +6045,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T07:36:36+00:00" + "time": "2024-10-03T09:19:10+00:00" }, { "name": "symfony/routing", - "version": "v7.1.4", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "1500aee0094a3ce1c92626ed8cf3c2037e86f5a7" + "reference": "b9f47730638e96d6ff26f84bd4a7e89073d15634" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/1500aee0094a3ce1c92626ed8cf3c2037e86f5a7", - "reference": "1500aee0094a3ce1c92626ed8cf3c2037e86f5a7", + "url": "https://api.github.com/repos/symfony/routing/zipball/b9f47730638e96d6ff26f84bd4a7e89073d15634", + "reference": "b9f47730638e96d6ff26f84bd4a7e89073d15634", "shasum": "" }, "require": { @@ -6105,7 +6110,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.1.4" + "source": "https://github.com/symfony/routing/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6121,20 +6126,20 @@ "type": "tidelift" } ], - "time": "2024-08-29T08:16:25+00:00" + "time": "2024-10-03T12:20:01+00:00" }, { "name": "symfony/runtime", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "ea34522c447dd91a2b31cb330ee4540a56ba53f6" + "reference": "049a9f3bebe7d4d9572e3d4a86f0fb7fe24fb077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/ea34522c447dd91a2b31cb330ee4540a56ba53f6", - "reference": "ea34522c447dd91a2b31cb330ee4540a56ba53f6", + "url": "https://api.github.com/repos/symfony/runtime/zipball/049a9f3bebe7d4d9572e3d4a86f0fb7fe24fb077", + "reference": "049a9f3bebe7d4d9572e3d4a86f0fb7fe24fb077", "shasum": "" }, "require": { @@ -6184,7 +6189,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v7.1.1" + "source": "https://github.com/symfony/runtime/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6200,20 +6205,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:55:39+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/serializer", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "71d6e1f70f00752d1469d0f5e83b0a51716f288b" + "reference": "56bcd41f8e8792b15ca363b730e26c7c536a7873" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/71d6e1f70f00752d1469d0f5e83b0a51716f288b", - "reference": "71d6e1f70f00752d1469d0f5e83b0a51716f288b", + "url": "https://api.github.com/repos/symfony/serializer/zipball/56bcd41f8e8792b15ca363b730e26c7c536a7873", + "reference": "56bcd41f8e8792b15ca363b730e26c7c536a7873", "shasum": "" }, "require": { @@ -6239,7 +6244,7 @@ "symfony/cache": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dependency-injection": "^7.2", "symfony/error-handler": "^6.4|^7.0", "symfony/filesystem": "^6.4|^7.0", "symfony/form": "^6.4|^7.0", @@ -6283,7 +6288,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v7.1.5" + "source": "https://github.com/symfony/serializer/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6299,7 +6304,7 @@ "type": "tidelift" } ], - "time": "2024-09-20T12:13:15+00:00" + "time": "2024-10-22T19:37:21+00:00" }, { "name": "symfony/service-contracts", @@ -6390,12 +6395,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/stimulus-bundle.git", - "reference": "e5f7747b514865719e0990389ce35a9b71bebb48" + "reference": "2dc5431fd4fd84662615b435af7a0a6affd94f2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/e5f7747b514865719e0990389ce35a9b71bebb48", - "reference": "e5f7747b514865719e0990389ce35a9b71bebb48", + "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/2dc5431fd4fd84662615b435af7a0a6affd94f2d", + "reference": "2dc5431fd4fd84662615b435af7a0a6affd94f2d", "shasum": "" }, "require": { @@ -6436,7 +6441,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/stimulus-bundle/tree/v2.21.0" + "source": "https://github.com/symfony/stimulus-bundle/tree/2.x" }, "funding": [ { @@ -6452,20 +6457,20 @@ "type": "tidelift" } ], - "time": "2024-10-05T22:11:16+00:00" + "time": "2024-10-28T11:18:16+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "5b75bb1ac2ba1b9d05c47fc4b3046a625377d23d" + "reference": "696f418b0d722a4225e1c3d95489d262971ca924" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5b75bb1ac2ba1b9d05c47fc4b3046a625377d23d", - "reference": "5b75bb1ac2ba1b9d05c47fc4b3046a625377d23d", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/696f418b0d722a4225e1c3d95489d262971ca924", + "reference": "696f418b0d722a4225e1c3d95489d262971ca924", "shasum": "" }, "require": { @@ -6498,7 +6503,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.1.1" + "source": "https://github.com/symfony/stopwatch/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6514,20 +6519,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/string", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306" + "reference": "205580699b4d3e11f7b679faf2c0f57ffca6981c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306", - "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306", + "url": "https://api.github.com/repos/symfony/string/zipball/205580699b4d3e11f7b679faf2c0f57ffca6981c", + "reference": "205580699b4d3e11f7b679faf2c0f57ffca6981c", "shasum": "" }, "require": { @@ -6585,7 +6590,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.5" + "source": "https://github.com/symfony/string/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6601,24 +6606,25 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfony/translation", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "235535e3f84f3dfbdbde0208ede6ca75c3a489ea" + "reference": "f1faf9a381d39d0bf8ca1c10cab7dcf41fba50dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/235535e3f84f3dfbdbde0208ede6ca75c3a489ea", - "reference": "235535e3f84f3dfbdbde0208ede6ca75c3a489ea", + "url": "https://api.github.com/repos/symfony/translation/zipball/f1faf9a381d39d0bf8ca1c10cab7dcf41fba50dc", + "reference": "f1faf9a381d39d0bf8ca1c10cab7dcf41fba50dc", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/translation-contracts": "^2.5|^3.0" }, @@ -6679,7 +6685,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.1.5" + "source": "https://github.com/symfony/translation/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6695,7 +6701,7 @@ "type": "tidelift" } ], - "time": "2024-09-16T06:30:38+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfony/translation-contracts", @@ -6777,22 +6783,23 @@ }, { "name": "symfony/twig-bridge", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "e997e5025b53c0f7b17632802daefdd6a04540ae" + "reference": "a5d88e50935a998eb84495098f2d1e3aa75de627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e997e5025b53c0f7b17632802daefdd6a04540ae", - "reference": "e997e5025b53c0f7b17632802daefdd6a04540ae", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/a5d88e50935a998eb84495098f2d1e3aa75de627", + "reference": "a5d88e50935a998eb84495098f2d1e3aa75de627", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/translation-contracts": "^2.5|^3", - "twig/twig": "^3.9" + "twig/twig": "^3.12" }, "conflict": { "phpdocumentor/reflection-docblock": "<3.2.2", @@ -6866,7 +6873,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v7.1.5" + "source": "https://github.com/symfony/twig-bridge/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6882,20 +6889,20 @@ "type": "tidelift" } ], - "time": "2024-09-15T06:48:17+00:00" + "time": "2024-10-25T16:06:58+00:00" }, { "name": "symfony/twig-bundle", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "4e6afd0dc8396f16861b682f3b854ff6e24bfb7e" + "reference": "cd2be4563afaef5285bb6e0a06c5445e644a5c01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/4e6afd0dc8396f16861b682f3b854ff6e24bfb7e", - "reference": "4e6afd0dc8396f16861b682f3b854ff6e24bfb7e", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/cd2be4563afaef5285bb6e0a06c5445e644a5c01", + "reference": "cd2be4563afaef5285bb6e0a06c5445e644a5c01", "shasum": "" }, "require": { @@ -6906,7 +6913,7 @@ "symfony/http-foundation": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", "symfony/twig-bridge": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, "conflict": { "symfony/framework-bundle": "<6.4", @@ -6950,7 +6957,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/v7.1.5" + "source": "https://github.com/symfony/twig-bundle/tree/v7.2.0-BETA1" }, "funding": [ { @@ -6966,20 +6973,20 @@ "type": "tidelift" } ], - "time": "2024-09-08T12:32:26+00:00" + "time": "2024-10-23T08:11:15+00:00" }, { "name": "symfony/type-info", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "9f6094aa900d2c06bd61576a6f279d4ac441515f" + "reference": "fdac72a37de68564ff83ea2c2a3e9b0b2245d3bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/9f6094aa900d2c06bd61576a6f279d4ac441515f", - "reference": "9f6094aa900d2c06bd61576a6f279d4ac441515f", + "url": "https://api.github.com/repos/symfony/type-info/zipball/fdac72a37de68564ff83ea2c2a3e9b0b2245d3bd", + "reference": "fdac72a37de68564ff83ea2c2a3e9b0b2245d3bd", "shasum": "" }, "require": { @@ -7032,7 +7039,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v7.1.5" + "source": "https://github.com/symfony/type-info/tree/v7.2.0-BETA1" }, "funding": [ { @@ -7048,20 +7055,20 @@ "type": "tidelift" } ], - "time": "2024-09-19T21:48:23+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/uid", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "8c7bb8acb933964055215d89f9a9871df0239317" + "reference": "2d294d0c48df244c71c105a169d0190bfb080426" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/8c7bb8acb933964055215d89f9a9871df0239317", - "reference": "8c7bb8acb933964055215d89f9a9871df0239317", + "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426", "shasum": "" }, "require": { @@ -7106,7 +7113,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.1.5" + "source": "https://github.com/symfony/uid/tree/v7.2.0-BETA1" }, "funding": [ { @@ -7122,7 +7129,7 @@ "type": "tidelift" } ], - "time": "2024-09-17T09:16:35+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/ux-autocomplete", @@ -7130,12 +7137,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-autocomplete.git", - "reference": "357a4b8eef612b279568292a878e60b8b0992413" + "reference": "c1681c9b8fc3aa09657e02b8842be69102918a89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-autocomplete/zipball/357a4b8eef612b279568292a878e60b8b0992413", - "reference": "357a4b8eef612b279568292a878e60b8b0992413", + "url": "https://api.github.com/repos/symfony/ux-autocomplete/zipball/c1681c9b8fc3aa09657e02b8842be69102918a89", + "reference": "c1681c9b8fc3aa09657e02b8842be69102918a89", "shasum": "" }, "require": { @@ -7197,7 +7204,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-autocomplete/tree/v2.21.0" + "source": "https://github.com/symfony/ux-autocomplete/tree/2.x" }, "funding": [ { @@ -7213,7 +7220,7 @@ "type": "tidelift" } ], - "time": "2024-10-21T19:02:15+00:00" + "time": "2024-10-24T09:16:33+00:00" }, { "name": "symfony/ux-chartjs", @@ -7468,12 +7475,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-icons.git", - "reference": "c3b3fd29b3f90e977b267251ef15ea06f3cec553" + "reference": "b409bc7427957ba931589d16f42c145eeb4fb148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-icons/zipball/c3b3fd29b3f90e977b267251ef15ea06f3cec553", - "reference": "c3b3fd29b3f90e977b267251ef15ea06f3cec553", + "url": "https://api.github.com/repos/symfony/ux-icons/zipball/b409bc7427957ba931589d16f42c145eeb4fb148", + "reference": "b409bc7427957ba931589d16f42c145eeb4fb148", "shasum": "" }, "require": { @@ -7534,7 +7541,7 @@ "twig" ], "support": { - "source": "https://github.com/symfony/ux-icons/tree/v2.21.0" + "source": "https://github.com/symfony/ux-icons/tree/2.x" }, "funding": [ { @@ -7550,7 +7557,7 @@ "type": "tidelift" } ], - "time": "2024-10-21T19:01:22+00:00" + "time": "2024-10-31T16:56:54+00:00" }, { "name": "symfony/ux-lazy-image", @@ -7708,16 +7715,17 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-live-component.git", - "reference": "1cc963a50a31a8ca92fbd145b29b27231b199b1b" + "reference": "b1727573b4bff5821958306c6360668aac82f6d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/1cc963a50a31a8ca92fbd145b29b27231b199b1b", - "reference": "1cc963a50a31a8ca92fbd145b29b27231b199b1b", + "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/b1727573b4bff5821958306c6360668aac82f6d3", + "reference": "b1727573b4bff5821958306c6360668aac82f6d3", "shasum": "" }, "require": { "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/property-access": "^5.4.5|^6.0|^7.0", "symfony/stimulus-bundle": "^2.9", "symfony/ux-twig-component": "^2.8", @@ -7778,7 +7786,7 @@ "twig" ], "support": { - "source": "https://github.com/symfony/ux-live-component/tree/v2.21.0" + "source": "https://github.com/symfony/ux-live-component/tree/2.x" }, "funding": [ { @@ -7794,7 +7802,7 @@ "type": "tidelift" } ], - "time": "2024-10-15T10:36:54+00:00" + "time": "2024-10-31T16:39:49+00:00" }, { "name": "symfony/ux-map", @@ -8352,12 +8360,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-turbo.git", - "reference": "075c609e54fc421c6b1c1974e46e9a8b2d44277c" + "reference": "add0a143c032a482c07c8d5e8776270973491abd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/075c609e54fc421c6b1c1974e46e9a8b2d44277c", - "reference": "075c609e54fc421c6b1c1974e46e9a8b2d44277c", + "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/add0a143c032a482c07c8d5e8776270973491abd", + "reference": "add0a143c032a482c07c8d5e8776270973491abd", "shasum": "" }, "require": { @@ -8427,7 +8435,7 @@ "turbo-stream" ], "support": { - "source": "https://github.com/symfony/ux-turbo/tree/v2.21.0" + "source": "https://github.com/symfony/ux-turbo/tree/2.x" }, "funding": [ { @@ -8443,7 +8451,7 @@ "type": "tidelift" } ], - "time": "2024-10-21T19:07:02+00:00" + "time": "2024-10-30T20:05:58+00:00" }, { "name": "symfony/ux-twig-component", @@ -8451,12 +8459,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-twig-component.git", - "reference": "5b60b239fffcb04fc8bdb2a5a4001d19442d575d" + "reference": "da12467494cbf4adc91384f7ace7063e315b7445" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/5b60b239fffcb04fc8bdb2a5a4001d19442d575d", - "reference": "5b60b239fffcb04fc8bdb2a5a4001d19442d575d", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/da12467494cbf4adc91384f7ace7063e315b7445", + "reference": "da12467494cbf4adc91384f7ace7063e315b7445", "shasum": "" }, "require": { @@ -8511,7 +8519,7 @@ "twig" ], "support": { - "source": "https://github.com/symfony/ux-twig-component/tree/v2.21.0" + "source": "https://github.com/symfony/ux-twig-component/tree/2.x" }, "funding": [ { @@ -8527,7 +8535,7 @@ "type": "tidelift" } ], - "time": "2024-10-05T22:11:16+00:00" + "time": "2024-11-01T06:57:32+00:00" }, { "name": "symfony/ux-typed", @@ -8680,16 +8688,16 @@ }, { "name": "symfony/validator", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "e57592782dc2a86997477f28164c51af53512ad8" + "reference": "8392b9bafbfed3c166a979ac0bd8a3186abb8e75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/e57592782dc2a86997477f28164c51af53512ad8", - "reference": "e57592782dc2a86997477f28164c51af53512ad8", + "url": "https://api.github.com/repos/symfony/validator/zipball/8392b9bafbfed3c166a979ac0bd8a3186abb8e75", + "reference": "8392b9bafbfed3c166a979ac0bd8a3186abb8e75", "shasum": "" }, "require": { @@ -8757,7 +8765,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v7.1.5" + "source": "https://github.com/symfony/validator/tree/v7.2.0-BETA1" }, "funding": [ { @@ -8773,20 +8781,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:28:38+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "e20e03889539fd4e4211e14d2179226c513c010d" + "reference": "b86ce1b5bb196cfb3796856979167271d3989c7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e20e03889539fd4e4211e14d2179226c513c010d", - "reference": "e20e03889539fd4e4211e14d2179226c513c010d", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b86ce1b5bb196cfb3796856979167271d3989c7c", + "reference": "b86ce1b5bb196cfb3796856979167271d3989c7c", "shasum": "" }, "require": { @@ -8802,7 +8810,7 @@ "symfony/http-kernel": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", "symfony/uid": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, "bin": [ "Resources/bin/var-dump-server" @@ -8840,7 +8848,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.1.5" + "source": "https://github.com/symfony/var-dumper/tree/v7.2.0-BETA1" }, "funding": [ { @@ -8856,20 +8864,20 @@ "type": "tidelift" } ], - "time": "2024-09-16T10:07:02+00:00" + "time": "2024-10-23T08:11:15+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.1.2", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "b80a669a2264609f07f1667f891dbfca25eba44c" + "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b80a669a2264609f07f1667f891dbfca25eba44c", - "reference": "b80a669a2264609f07f1667f891dbfca25eba44c", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1a6a89f95a46af0f142874c9d650a6358d13070d", + "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d", "shasum": "" }, "require": { @@ -8916,7 +8924,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.1.2" + "source": "https://github.com/symfony/var-exporter/tree/v7.2.0-BETA1" }, "funding": [ { @@ -8932,20 +8940,20 @@ "type": "tidelift" } ], - "time": "2024-06-28T08:00:31+00:00" + "time": "2024-10-18T07:58:17+00:00" }, { "name": "symfony/web-link", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/web-link.git", - "reference": "63f90aa0054bfd9a091d2f5cf465958f1030638f" + "reference": "f537556a885e14a1d28f6c759d41e57e93d0a532" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-link/zipball/63f90aa0054bfd9a091d2f5cf465958f1030638f", - "reference": "63f90aa0054bfd9a091d2f5cf465958f1030638f", + "url": "https://api.github.com/repos/symfony/web-link/zipball/f537556a885e14a1d28f6c759d41e57e93d0a532", + "reference": "f537556a885e14a1d28f6c759d41e57e93d0a532", "shasum": "" }, "require": { @@ -8999,7 +9007,7 @@ "push" ], "support": { - "source": "https://github.com/symfony/web-link/tree/v7.1.1" + "source": "https://github.com/symfony/web-link/tree/v7.2.0-BETA1" }, "funding": [ { @@ -9015,24 +9023,25 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/yaml", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "4e561c316e135e053bd758bf3b3eb291d9919de4" + "reference": "099581e99f557e9f16b43c5916c26380b54abb22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/4e561c316e135e053bd758bf3b3eb291d9919de4", - "reference": "4e561c316e135e053bd758bf3b3eb291d9919de4", + "url": "https://api.github.com/repos/symfony/yaml/zipball/099581e99f557e9f16b43c5916c26380b54abb22", + "reference": "099581e99f557e9f16b43c5916c26380b54abb22", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -9070,7 +9079,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.1.5" + "source": "https://github.com/symfony/yaml/tree/v7.2.0-BETA1" }, "funding": [ { @@ -9086,7 +9095,7 @@ "type": "tidelift" } ], - "time": "2024-09-17T12:49:58+00:00" + "time": "2024-10-23T06:56:12+00:00" }, { "name": "symfonycasts/dynamic-forms", @@ -9144,16 +9153,16 @@ }, { "name": "symfonycasts/sass-bundle", - "version": "v0.6.0", + "version": "v0.8.1", "source": { "type": "git", "url": "https://github.com/SymfonyCasts/sass-bundle.git", - "reference": "aa47da8ae43136a21a764eedb1471f2a168359cb" + "reference": "4637a176b5adfb03f83c409c3f9f566e30426318" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SymfonyCasts/sass-bundle/zipball/aa47da8ae43136a21a764eedb1471f2a168359cb", - "reference": "aa47da8ae43136a21a764eedb1471f2a168359cb", + "url": "https://api.github.com/repos/SymfonyCasts/sass-bundle/zipball/4637a176b5adfb03f83c409c3f9f566e30426318", + "reference": "4637a176b5adfb03f83c409c3f9f566e30426318", "shasum": "" }, "require": { @@ -9166,9 +9175,9 @@ }, "require-dev": { "matthiasnoback/symfony-config-test": "^5.0", - "phpstan/phpstan-symfony": "^1.4", + "phpunit/phpunit": "^9.6", "symfony/framework-bundle": "^6.3|^7.0", - "symfony/phpunit-bridge": "^6.3|^7.0" + "symfony/phpunit-bridge": "^6.3.9|^7.0" }, "type": "library", "autoload": { @@ -9193,22 +9202,22 @@ ], "support": { "issues": "https://github.com/SymfonyCasts/sass-bundle/issues", - "source": "https://github.com/SymfonyCasts/sass-bundle/tree/v0.6.0" + "source": "https://github.com/SymfonyCasts/sass-bundle/tree/v0.8.1" }, - "time": "2024-02-26T10:09:48+00:00" + "time": "2024-10-17T10:46:06+00:00" }, { "name": "tempest/highlight", - "version": "2.10.5", + "version": "2.10.6", "source": { "type": "git", "url": "https://github.com/tempestphp/highlight.git", - "reference": "2d119afdac7aa98927dbbcf239e5cff86b74faf0" + "reference": "00ef935cc68b1b1ba68ffb09e91a810e42ca4e9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tempestphp/highlight/zipball/2d119afdac7aa98927dbbcf239e5cff86b74faf0", - "reference": "2d119afdac7aa98927dbbcf239e5cff86b74faf0", + "url": "https://api.github.com/repos/tempestphp/highlight/zipball/00ef935cc68b1b1ba68ffb09e91a810e42ca4e9d", + "reference": "00ef935cc68b1b1ba68ffb09e91a810e42ca4e9d", "shasum": "" }, "require": { @@ -9245,7 +9254,7 @@ "description": "Fast, extensible, server-side code highlighting", "support": { "issues": "https://github.com/tempestphp/highlight/issues", - "source": "https://github.com/tempestphp/highlight/tree/2.10.5" + "source": "https://github.com/tempestphp/highlight/tree/2.10.6" }, "funding": [ { @@ -9253,7 +9262,7 @@ "type": "github" } ], - "time": "2024-10-20T04:44:15+00:00" + "time": "2024-10-24T06:44:39+00:00" }, { "name": "twbs/bootstrap", @@ -9733,16 +9742,16 @@ "packages-dev": [ { "name": "behat/mink", - "version": "v1.11.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/minkphp/Mink.git", - "reference": "d8527fdf8785aad38455fb426af457ab9937aece" + "reference": "7e4edec6c335937029cb3569ce7ef81182804d0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/minkphp/Mink/zipball/d8527fdf8785aad38455fb426af457ab9937aece", - "reference": "d8527fdf8785aad38455fb426af457ab9937aece", + "url": "https://api.github.com/repos/minkphp/Mink/zipball/7e4edec6c335937029cb3569ce7ef81182804d0a", + "reference": "7e4edec6c335937029cb3569ce7ef81182804d0a", "shasum": "" }, "require": { @@ -9793,9 +9802,9 @@ ], "support": { "issues": "https://github.com/minkphp/Mink/issues", - "source": "https://github.com/minkphp/Mink/tree/v1.11.0" + "source": "https://github.com/minkphp/Mink/tree/v1.12.0" }, - "time": "2023-12-09T11:23:23+00:00" + "time": "2024-10-30T18:48:14+00:00" }, { "name": "fakerphp/faker", @@ -11550,16 +11559,16 @@ }, { "name": "symfony/browser-kit", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "9c13742e3175b5815e272b981876ae329bec2040" + "reference": "8d64d17e198082f8f198d023a6b634e7b5fdda94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/9c13742e3175b5815e272b981876ae329bec2040", - "reference": "9c13742e3175b5815e272b981876ae329bec2040", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/8d64d17e198082f8f198d023a6b634e7b5fdda94", + "reference": "8d64d17e198082f8f198d023a6b634e7b5fdda94", "shasum": "" }, "require": { @@ -11598,7 +11607,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v7.1.1" + "source": "https://github.com/symfony/browser-kit/tree/v7.2.0-BETA1" }, "funding": [ { @@ -11614,20 +11623,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/css-selector", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "1c7cee86c6f812896af54434f8ce29c8d94f9ff4" + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/1c7cee86c6f812896af54434f8ce29c8d94f9ff4", - "reference": "1c7cee86c6f812896af54434f8ce29c8d94f9ff4", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", "shasum": "" }, "require": { @@ -11663,7 +11672,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.1.1" + "source": "https://github.com/symfony/css-selector/tree/v7.2.0-BETA1" }, "funding": [ { @@ -11679,20 +11688,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/debug-bundle", - "version": "v7.1.1", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "aa024d28ce7ce0c6a16ee57c066838bece92893f" + "reference": "2dade0d1415c08b627379b5ec214ec8424cb2e32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/aa024d28ce7ce0c6a16ee57c066838bece92893f", - "reference": "aa024d28ce7ce0c6a16ee57c066838bece92893f", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/2dade0d1415c08b627379b5ec214ec8424cb2e32", + "reference": "2dade0d1415c08b627379b5ec214ec8424cb2e32", "shasum": "" }, "require": { @@ -11737,7 +11746,7 @@ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug-bundle/tree/v7.1.1" + "source": "https://github.com/symfony/debug-bundle/tree/v7.2.0-BETA1" }, "funding": [ { @@ -11753,20 +11762,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:55:39+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/dom-crawler", - "version": "v7.1.5", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "b92af238457a7cdd2738f941cd525d76313e8283" + "reference": "3e838f9095f53f2b98287a361c1cdb68bbd3aa7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b92af238457a7cdd2738f941cd525d76313e8283", - "reference": "b92af238457a7cdd2738f941cd525d76313e8283", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/3e838f9095f53f2b98287a361c1cdb68bbd3aa7b", + "reference": "3e838f9095f53f2b98287a361c1cdb68bbd3aa7b", "shasum": "" }, "require": { @@ -11804,7 +11813,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v7.1.5" + "source": "https://github.com/symfony/dom-crawler/tree/v7.2.0-BETA1" }, "funding": [ { @@ -11820,7 +11829,7 @@ "type": "tidelift" } ], - "time": "2024-09-15T06:48:17+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/maker-bundle", @@ -11916,16 +11925,16 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v7.1.4", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "e876eb90e32a8fc4c4911d458e09f88d65877d1c" + "reference": "078398ebac9b707438286e8d689b30b5ef1e6602" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/e876eb90e32a8fc4c4911d458e09f88d65877d1c", - "reference": "e876eb90e32a8fc4c4911d458e09f88d65877d1c", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/078398ebac9b707438286e8d689b30b5ef1e6602", + "reference": "078398ebac9b707438286e8d689b30b5ef1e6602", "shasum": "" }, "require": { @@ -11978,7 +11987,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.1.4" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.2.0-BETA1" }, "funding": [ { @@ -11994,20 +12003,20 @@ "type": "tidelift" } ], - "time": "2024-08-13T14:28:19+00:00" + "time": "2024-10-23T06:50:56+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v7.1.4", + "version": "v7.2.0-BETA1", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "3cfc775277a8f2dacdd0f72d196bc87b272a763f" + "reference": "1827c2cf600a760334b4fbbc610a9fe308a3f73a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/3cfc775277a8f2dacdd0f72d196bc87b272a763f", - "reference": "3cfc775277a8f2dacdd0f72d196bc87b272a763f", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/1827c2cf600a760334b4fbbc610a9fe308a3f73a", + "reference": "1827c2cf600a760334b4fbbc610a9fe308a3f73a", "shasum": "" }, "require": { @@ -12017,12 +12026,13 @@ "symfony/http-kernel": "^6.4|^7.0", "symfony/routing": "^6.4|^7.0", "symfony/twig-bundle": "^6.4|^7.0", - "twig/twig": "^3.10" + "twig/twig": "^3.12" }, "conflict": { "symfony/form": "<6.4", "symfony/mailer": "<6.4", - "symfony/messenger": "<6.4" + "symfony/messenger": "<6.4", + "symfony/serializer": "<7.2" }, "require-dev": { "symfony/browser-kit": "^6.4|^7.0", @@ -12059,7 +12069,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.1.4" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.2.0-BETA1" }, "funding": [ { @@ -12075,7 +12085,7 @@ "type": "tidelift" } ], - "time": "2024-08-12T09:59:40+00:00" + "time": "2024-10-23T08:11:15+00:00" }, { "name": "theseer/tokenizer", @@ -12267,16 +12277,16 @@ }, { "name": "zenstruck/assert", - "version": "v1.5.0", + "version": "v1.5.1", "source": { "type": "git", "url": "https://github.com/zenstruck/assert.git", - "reference": "60956bb6584a51c6c2ab9fa8707b7c013d770163" + "reference": "39554ce3a275fbf8c870b251e620101f644e9277" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/assert/zipball/60956bb6584a51c6c2ab9fa8707b7c013d770163", - "reference": "60956bb6584a51c6c2ab9fa8707b7c013d770163", + "url": "https://api.github.com/repos/zenstruck/assert/zipball/39554ce3a275fbf8c870b251e620101f644e9277", + "reference": "39554ce3a275fbf8c870b251e620101f644e9277", "shasum": "" }, "require": { @@ -12286,8 +12296,8 @@ }, "require-dev": { "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^9.5", - "symfony/phpunit-bridge": "^6.3" + "phpunit/phpunit": "^9.5.21", + "symfony/phpunit-bridge": "^6.3|^7.0" }, "type": "library", "autoload": { @@ -12314,7 +12324,7 @@ ], "support": { "issues": "https://github.com/zenstruck/assert/issues", - "source": "https://github.com/zenstruck/assert/tree/v1.5.0" + "source": "https://github.com/zenstruck/assert/tree/v1.5.1" }, "funding": [ { @@ -12322,7 +12332,7 @@ "type": "github" } ], - "time": "2023-12-02T09:08:04+00:00" + "time": "2024-10-28T18:08:12+00:00" }, { "name": "zenstruck/browser", @@ -12456,16 +12466,16 @@ }, { "name": "zenstruck/foundry", - "version": "v2.0.9", + "version": "v2.2.1", "source": { "type": "git", "url": "https://github.com/zenstruck/foundry.git", - "reference": "b0a5d3d8b43acd4b0f356c6dcfdec6c8ebff1c08" + "reference": "4743a9da142b42d484ac7a99c1a7068aa66c7bec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/foundry/zipball/b0a5d3d8b43acd4b0f356c6dcfdec6c8ebff1c08", - "reference": "b0a5d3d8b43acd4b0f356c6dcfdec6c8ebff1c08", + "url": "https://api.github.com/repos/zenstruck/foundry/zipball/4743a9da142b42d484ac7a99c1a7068aa66c7bec", + "reference": "4743a9da142b42d484ac7a99c1a7068aa66c7bec", "shasum": "" }, "require": { @@ -12502,6 +12512,9 @@ "target-directory": "bin/tools", "bin-links": true, "forward-command": false + }, + "psalm": { + "pluginClass": "Zenstruck\\Foundry\\Psalm\\FoundryPlugin" } }, "autoload": { @@ -12511,7 +12524,8 @@ "src/phpunit_helper.php" ], "psr-4": { - "Zenstruck\\Foundry\\": "src/" + "Zenstruck\\Foundry\\": "src/", + "Zenstruck\\Foundry\\Psalm\\": "utils/psalm" } }, "notification-url": "https://packagist.org/downloads/", @@ -12541,7 +12555,7 @@ ], "support": { "issues": "https://github.com/zenstruck/foundry/issues", - "source": "https://github.com/zenstruck/foundry/tree/v2.0.9" + "source": "https://github.com/zenstruck/foundry/tree/v2.2.1" }, "funding": [ { @@ -12549,7 +12563,7 @@ "type": "github" } ], - "time": "2024-09-02T18:20:52+00:00" + "time": "2024-10-31T12:10:58+00:00" } ], "aliases": [], diff --git a/ux.symfony.com/config/packages/symfonycasts_sass.yaml b/ux.symfony.com/config/packages/symfonycasts_sass.yaml new file mode 100644 index 00000000000..041d1e288e9 --- /dev/null +++ b/ux.symfony.com/config/packages/symfonycasts_sass.yaml @@ -0,0 +1,5 @@ +symfonycasts_sass: + sass_options: + style: compressed + source_map: false + quiet: true # silence deprecation warnings From 551738847ea09c916986742e832c0269fbc80f4d Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Fri, 1 Nov 2024 19:22:41 +0100 Subject: [PATCH 04/42] =?UTF-8?q?[DX]=C2=A0Add=20lint/format/check-lint/ch?= =?UTF-8?q?eck-format=20scripts=20to=20packages=20package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 8 ++++---- src/Autocomplete/assets/package.json | 8 ++++++++ src/Chartjs/assets/package.json | 8 ++++++++ src/Cropperjs/assets/package.json | 8 ++++++++ src/Dropzone/assets/package.json | 8 ++++++++ src/LazyImage/assets/package.json | 8 ++++++++ src/LiveComponent/assets/package.json | 8 ++++++++ src/Map/assets/package.json | 8 ++++++++ src/Map/src/Bridge/Google/assets/package.json | 8 ++++++++ src/Map/src/Bridge/Leaflet/assets/package.json | 8 ++++++++ src/Notify/assets/package.json | 8 ++++++++ src/React/assets/package.json | 8 ++++++++ src/StimulusBundle/assets/package.json | 8 ++++++++ src/Svelte/assets/package.json | 8 ++++++++ src/Swup/assets/package.json | 8 ++++++++ src/TogglePassword/assets/package.json | 8 ++++++++ src/Translator/assets/package.json | 8 ++++++++ src/Turbo/assets/package.json | 8 ++++++++ src/Typed/assets/package.json | 8 ++++++++ src/Vue/assets/package.json | 8 ++++++++ 20 files changed, 156 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 3811ae9cf87..e117c5a1c9c 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "scripts": { "build": "node bin/build_javascript.js && node bin/build_styles.js", "test": "bin/run-vitest-all.sh", - "lint": "biome lint --write", - "format": "biome format --write", - "check-lint": "biome lint", - "check-format": "biome format" + "lint": "yarn workspaces foreach --all -pt run lint", + "format": "yarn workspaces foreach --all -pt run format", + "check-lint": "yarn workspaces foreach --all -pt run check-lint", + "check-format": "yarn workspaces foreach --all -pt run check-format" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/src/Autocomplete/assets/package.json b/src/Autocomplete/assets/package.json index 8af1c434c31..204fb438d9c 100644 --- a/src/Autocomplete/assets/package.json +++ b/src/Autocomplete/assets/package.json @@ -5,6 +5,14 @@ "types": "dist/controller.d.ts", "version": "1.0.0", "license": "MIT", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "autocomplete": { diff --git a/src/Chartjs/assets/package.json b/src/Chartjs/assets/package.json index ed730622523..3b067838de0 100644 --- a/src/Chartjs/assets/package.json +++ b/src/Chartjs/assets/package.json @@ -6,6 +6,14 @@ "type": "module", "main": "dist/controller.js", "types": "dist/controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "chart": { diff --git a/src/Cropperjs/assets/package.json b/src/Cropperjs/assets/package.json index 2133ce56e97..ae59f6c36e7 100644 --- a/src/Cropperjs/assets/package.json +++ b/src/Cropperjs/assets/package.json @@ -8,6 +8,14 @@ "config": { "css_source": "src/style.css" }, + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "cropper": { diff --git a/src/Dropzone/assets/package.json b/src/Dropzone/assets/package.json index 1fc19df7ed1..ce35745715e 100644 --- a/src/Dropzone/assets/package.json +++ b/src/Dropzone/assets/package.json @@ -8,6 +8,14 @@ "config": { "css_source": "src/style.css" }, + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "dropzone": { diff --git a/src/LazyImage/assets/package.json b/src/LazyImage/assets/package.json index cc320117158..ddee00a915b 100644 --- a/src/LazyImage/assets/package.json +++ b/src/LazyImage/assets/package.json @@ -5,6 +5,14 @@ "version": "1.1.0", "main": "dist/controller.js", "types": "dist/controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "lazy-image": { diff --git a/src/LiveComponent/assets/package.json b/src/LiveComponent/assets/package.json index a0d5dba4a10..0824d49b1a1 100644 --- a/src/LiveComponent/assets/package.json +++ b/src/LiveComponent/assets/package.json @@ -8,6 +8,14 @@ "css_source": "styles/live.css" }, "license": "MIT", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "live": { diff --git a/src/Map/assets/package.json b/src/Map/assets/package.json index 4cd6dd529d2..4183d52794d 100644 --- a/src/Map/assets/package.json +++ b/src/Map/assets/package.json @@ -6,6 +6,14 @@ "type": "module", "main": "dist/abstract_map_controller.js", "types": "dist/abstract_map_controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "importmap": { "@hotwired/stimulus": "^3.0.0" diff --git a/src/Map/src/Bridge/Google/assets/package.json b/src/Map/src/Bridge/Google/assets/package.json index 8b8dfdbc8d7..d753fd25211 100644 --- a/src/Map/src/Bridge/Google/assets/package.json +++ b/src/Map/src/Bridge/Google/assets/package.json @@ -6,6 +6,14 @@ "type": "module", "main": "dist/map_controller.js", "types": "dist/map_controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "map": { diff --git a/src/Map/src/Bridge/Leaflet/assets/package.json b/src/Map/src/Bridge/Leaflet/assets/package.json index 3dd5663a147..496dad23ae0 100644 --- a/src/Map/src/Bridge/Leaflet/assets/package.json +++ b/src/Map/src/Bridge/Leaflet/assets/package.json @@ -6,6 +6,14 @@ "type": "module", "main": "dist/map_controller.js", "types": "dist/map_controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "map": { diff --git a/src/Notify/assets/package.json b/src/Notify/assets/package.json index 5f47e196287..10b05cb2768 100644 --- a/src/Notify/assets/package.json +++ b/src/Notify/assets/package.json @@ -5,6 +5,14 @@ "version": "1.0.0", "main": "dist/controller.js", "types": "dist/controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "notify": { diff --git a/src/React/assets/package.json b/src/React/assets/package.json index a4f7f6753d6..ba9ba75ca7a 100644 --- a/src/React/assets/package.json +++ b/src/React/assets/package.json @@ -5,6 +5,14 @@ "version": "1.0.0", "main": "dist/register_controller.js", "types": "dist/register_controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "react": { diff --git a/src/StimulusBundle/assets/package.json b/src/StimulusBundle/assets/package.json index 03cf5905649..11022825165 100644 --- a/src/StimulusBundle/assets/package.json +++ b/src/StimulusBundle/assets/package.json @@ -4,6 +4,14 @@ "version": "1.0.0", "license": "MIT", "main": "dist/loader.js", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "needsPackageAsADependency": false, "importmap": { diff --git a/src/Svelte/assets/package.json b/src/Svelte/assets/package.json index 95eabf51129..aff845fe83f 100644 --- a/src/Svelte/assets/package.json +++ b/src/Svelte/assets/package.json @@ -4,6 +4,14 @@ "main": "dist/register_controller.js", "version": "1.0.0", "license": "MIT", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "svelte": { diff --git a/src/Swup/assets/package.json b/src/Swup/assets/package.json index 5e45461f451..03b574b2c94 100644 --- a/src/Swup/assets/package.json +++ b/src/Swup/assets/package.json @@ -5,6 +5,14 @@ "version": "1.1.0", "main": "dist/controller.js", "types": "dist/controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "swup": { diff --git a/src/TogglePassword/assets/package.json b/src/TogglePassword/assets/package.json index 928dd1adf78..1ea4193c111 100644 --- a/src/TogglePassword/assets/package.json +++ b/src/TogglePassword/assets/package.json @@ -8,6 +8,14 @@ "config": { "css_source": "src/style.css" }, + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "toggle-password": { diff --git a/src/Translator/assets/package.json b/src/Translator/assets/package.json index 53c12bbcac4..19cd6d4a38e 100644 --- a/src/Translator/assets/package.json +++ b/src/Translator/assets/package.json @@ -5,6 +5,14 @@ "version": "1.0.0", "main": "dist/translator_controller.js", "types": "dist/translator_controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "importmap": { "intl-messageformat": "^10.5.11", diff --git a/src/Turbo/assets/package.json b/src/Turbo/assets/package.json index 395ac24c607..a7c323227c9 100644 --- a/src/Turbo/assets/package.json +++ b/src/Turbo/assets/package.json @@ -6,6 +6,14 @@ "version": "0.1.0", "main": "dist/turbo_controller.js", "types": "dist/turbo_controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "turbo-core": { diff --git a/src/Typed/assets/package.json b/src/Typed/assets/package.json index e187dcab2bd..526f36b2592 100644 --- a/src/Typed/assets/package.json +++ b/src/Typed/assets/package.json @@ -5,6 +5,14 @@ "version": "1.0.0", "main": "dist/controller.js", "types": "dist/controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "typed": { diff --git a/src/Vue/assets/package.json b/src/Vue/assets/package.json index 05ec27f6094..31f53b93d2e 100644 --- a/src/Vue/assets/package.json +++ b/src/Vue/assets/package.json @@ -5,6 +5,14 @@ "version": "1.0.0", "main": "dist/register_controller.js", "types": "dist/register_controller.d.ts", + "scripts": { + "build": "echo 'The build script is not yet configured.' && exit 1", + "test": "echo 'The test script is not yet configured.' && exit 1", + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" + }, "symfony": { "controllers": { "vue": { From 1873b3eda623637a461a3609b64a6d5e81a4d6d8 Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sat, 2 Nov 2024 11:13:04 +0100 Subject: [PATCH 05/42] [DX] Rework building process, and add build/watch scripts to packages package.json --- bin/build_javascript.js | 43 ------ bin/build_package.js | 128 +++++++++++++++++ bin/build_styles.js | 46 ------- bin/rollup.js | 129 ++++++++++++++++++ package.json | 12 +- rollup.config.js | 115 ---------------- src/Autocomplete/assets/package.json | 3 +- src/Chartjs/assets/package.json | 3 +- src/Cropperjs/assets/package.json | 3 +- src/Dropzone/assets/package.json | 3 +- src/LazyImage/assets/package.json | 3 +- .../Component/plugins/QueryStringPluging.d.ts | 9 -- src/LiveComponent/assets/package.json | 3 +- src/Map/assets/package.json | 3 +- src/Map/src/Bridge/Google/assets/package.json | 3 +- .../src/Bridge/Leaflet/assets/package.json | 3 +- src/Notify/assets/package.json | 3 +- src/React/assets/package.json | 3 +- src/StimulusBundle/assets/package.json | 3 +- src/Svelte/assets/package.json | 3 +- src/Swup/assets/package.json | 3 +- src/TogglePassword/assets/package.json | 3 +- src/Translator/assets/package.json | 3 +- src/Turbo/assets/package.json | 3 +- src/Typed/assets/package.json | 3 +- src/Vue/assets/package.json | 3 +- yarn.lock | 110 ++------------- 27 files changed, 311 insertions(+), 338 deletions(-) delete mode 100644 bin/build_javascript.js create mode 100644 bin/build_package.js delete mode 100644 bin/build_styles.js create mode 100644 bin/rollup.js delete mode 100644 rollup.config.js delete mode 100644 src/LiveComponent/assets/dist/Component/plugins/QueryStringPluging.d.ts diff --git a/bin/build_javascript.js b/bin/build_javascript.js deleted file mode 100644 index 7f17622392c..00000000000 --- a/bin/build_javascript.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * This file is used to compile the TypeScript files in the assets/src directory - * of each package. - * - * It allows each package to spawn its own rollup process, which is necessary - * to keep memory usage down. - */ -const { spawnSync } = require('child_process'); -const glob = require('glob'); - -const files = [ - // custom handling for React - 'src/React/assets/src/loader.ts', - 'src/React/assets/src/components.ts', - // custom handling for Svelte - 'src/Svelte/assets/src/loader.ts', - 'src/Svelte/assets/src/components.ts', - // custom handling for Vue - 'src/Vue/assets/src/loader.ts', - 'src/Vue/assets/src/components.ts', - // custom handling for StimulusBundle - 'src/StimulusBundle/assets/src/loader.ts', - 'src/StimulusBundle/assets/src/controllers.ts', - // custom handling for Bridge - ...glob.sync('src/*/src/Bridge/*/assets/src/*controller.ts'), - ...glob.sync('src/*/assets/src/*controller.ts'), -]; - -files.forEach((file) => { - const result = spawnSync('node', [ - 'node_modules/.bin/rollup', - '-c', - '--environment', - `INPUT_FILE:${file}`, - ], { - stdio: 'inherit', - shell: true - }); - - if (result.error) { - console.error(`Error compiling ${file}:`, result.error); - } -}); diff --git a/bin/build_package.js b/bin/build_package.js new file mode 100644 index 00000000000..74be88a9c21 --- /dev/null +++ b/bin/build_package.js @@ -0,0 +1,128 @@ +/** + * This file is used to compile the assets from an UX package. + */ + +const { parseArgs } = require('node:util'); +const path = require('node:path'); +const fs = require('node:fs'); +const glob = require('glob'); +const rollup = require('rollup'); +const CleanCSS = require('clean-css'); +const { getRollupConfiguration } = require('./rollup'); + +const args = parseArgs({ + allowPositionals: true, + options: { + watch: { + type: 'boolean', + description: 'Watch the source files for changes and rebuild when necessary.', + }, + }, +}); + +async function main() { + const packageRoot = path.resolve(process.cwd(), args.positionals[0]); + + if (!fs.existsSync(packageRoot)) { + console.error(`The package directory "${packageRoot}" does not exist.`); + process.exit(1); + } + + if (!fs.existsSync(path.join(packageRoot, 'package.json'))) { + console.error(`The package directory "${packageRoot}" does not contain a package.json file.`); + process.exit(1); + } + + const packageData = require(path.join(packageRoot, 'package.json')); + const packageName = packageData.name; + const srcDir = path.join(packageRoot, 'src'); + const distDir = path.join(packageRoot, 'dist'); + + + if (!fs.existsSync(srcDir)) { + console.error(`The package directory "${packageRoot}" does not contain a "src" directory.`); + process.exit(1); + } + + if (fs.existsSync(distDir)) { + console.log(`Cleaning up the "${distDir}" directory...`); + await fs.promises.rm(distDir, { recursive: true }); + await fs.promises.mkdir(distDir); + } + + const inputScriptFiles = [ + ...glob.sync(path.join(srcDir, '*controller.ts')), + ...(['@symfony/ux-react', '@symfony/ux-vue', '@symfony/ux-svelte'].includes(packageName) + ? [ + path.join(srcDir, 'loader.ts'), + path.join(srcDir, 'components.ts'), + ] + : []), + ...(packageName === '@symfony/stimulus-bundle' + ? [ + path.join(srcDir, 'loader.ts'), + path.join(srcDir, 'controllers.ts'), + ] : []), + ]; + + const inputStyleFile = packageData.config && packageData.config.css_source; + const buildCss = async () => { + const inputStyleFileDist = inputStyleFile ? path.resolve(distDir, `${path.basename(inputStyleFile, '.css')}.min.css`) : undefined; + if (!inputStyleFile) { + return; + } + + console.log('Minifying CSS...'); + const css = await fs.promises.readFile(inputStyleFile, 'utf-8'); + const minified = new CleanCSS().minify(css).styles; + await fs.promises.writeFile(inputStyleFileDist, minified); + } + + if (inputScriptFiles.length === 0) { + console.error(`No input files found for package "${packageName}" (directory "${packageRoot}").\nEnsure you have at least a file matching the pattern "src/*_controller.ts", or manually specify input files in "${__filename}" file.`); + process.exit(1); + } + + const rollupConfig = getRollupConfiguration({ packageRoot, inputFiles: inputScriptFiles }); + + if (args.values.watch) { + console.log(`Watching for JavaScript${inputStyleFile ? ' and CSS' : ''} files modifications in "${srcDir}" directory...`); + + if (inputStyleFile) { + rollupConfig.plugins = (rollupConfig.plugins || []).concat({ + name: 'watcher', + buildStart() { + this.addWatchFile(inputStyleFile); + }, + }); + } + + const watcher = rollup.watch(rollupConfig); + watcher.on('event', ({ result }) => { + if (result) { + result.close(); + } + }); + watcher.on('change', async (id, { event }) => { + if (event === 'update') { + console.log(`Files were modified, rebuilding...`); + } + + if (inputStyleFile && id === inputStyleFile) { + await buildCss(); + } + }); + } else { + console.log(`Building JavaScript files from ${packageName} package...`); + const start = Date.now(); + + const bundle = await rollup.rollup(rollupConfig); + await bundle.write(rollupConfig.output); + + await buildCss(); + + console.log(`Done in ${((Date.now() - start) / 1000).toFixed(3)} seconds.`); + } +} + +main(); diff --git a/bin/build_styles.js b/bin/build_styles.js deleted file mode 100644 index ad45bb34b34..00000000000 --- a/bin/build_styles.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Script to "build" the source CSS files to their final destination. - */ - -const glob = require('glob'); -const { exec } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -let pattern = 'src/*/assets/package.json'; - -// Use glob to find all matching package.json files -glob(pattern, function (err, files) { - if (err) { - console.error('Error while finding package.json files:', err); - process.exit(1); - } - - // Loop over all files - files.forEach(file => { - // Read the package.json file - const pkg = JSON.parse(fs.readFileSync(file, 'utf-8')); - - // Get the css source - const cssSourceRelative = pkg.config && pkg.config.css_source; - - if (!cssSourceRelative) { - return; - } - // Construct the output path - const cssSource = path.join(path.dirname(file), cssSourceRelative); - const outputDir = path.join(path.dirname(file), 'dist'); - const outputFilename = path.basename(cssSource, '.css') + '.min.css'; - const output = path.join(outputDir, outputFilename); - - // Run the clean-css-cli command - exec(`yarn run cleancss -o ${output} ${cssSource}`, function (err) { - if (err) { - console.error(`Error while minifying ${cssSource}:`, err); - return; - } - - console.log(`Minified ${cssSource} to ${output}`); - }); - }); -}); diff --git a/bin/rollup.js b/bin/rollup.js new file mode 100644 index 00000000000..b3670dd98aa --- /dev/null +++ b/bin/rollup.js @@ -0,0 +1,129 @@ +const resolve = require('@rollup/plugin-node-resolve'); +const commonjs = require('@rollup/plugin-commonjs'); +const typescript = require('@rollup/plugin-typescript'); +const fs = require('fs'); +const glob = require('glob'); +const path = require('path'); + +/** + * Guarantees that any files imported from a peer dependency are treated as an external. + * + * For example, if we import `chart.js/auto`, that would not normally + * match the "chart.js" we pass to the "externals" config. This plugin + * catches that case and adds it as an external. + * + * Inspired by https://github.com/oat-sa/rollup-plugin-wildcard-external + */ +const wildcardExternalsPlugin = (peerDependencies) => ({ + name: 'wildcard-externals', + resolveId(source, importer) { + if (importer) { + let matchesExternal = false; + peerDependencies.forEach((peerDependency) => { + if (source.includes(`/${peerDependency}/`)) { + matchesExternal = true; + } + }); + + if (matchesExternal) { + return { + id: source, + external: true, + moduleSideEffects: true, + }; + } + } + + return null; // other ids should be handled as usually + }, +}); + +/** + * Moves the generated TypeScript declaration files to the correct location. + * + * This could probably be configured in the TypeScript plugin. + */ +const moveTypescriptDeclarationsPlugin = (packageRoot) => ({ + name: 'move-ts-declarations', + writeBundle: async () => { + const isBridge = packageRoot.includes('src/Bridge'); + const globPattern = path.join('dist', '**', 'assets', 'src', '**/*.d.ts'); + const files = glob.sync(globPattern); + + files.forEach((file) => { + const relativePath = file; + // a bit odd, but remove first 7 or 4 directories, which will leave only the relative path to the file + // ex: dist/Chartjs/assets/src/controller.d.ts' => 'dist/controller.d.ts' + const targetFile = relativePath.replace(relativePath.split('/').slice(1, isBridge ? 7 : 4).join('/') + '/', ''); + + if (!fs.existsSync(path.dirname(targetFile))) { + fs.mkdirSync(path.dirname(targetFile), { recursive: true }); + } + fs.renameSync(file, targetFile); + }); + }, +}); + +/** + * @param {String} packageRoot + * @param {Array} inputFiles + */ +function getRollupConfiguration({ packageRoot, inputFiles }) { + const packagePath = path.join(packageRoot, 'package.json'); + const packageData = JSON.parse(fs.readFileSync(packagePath, 'utf8')); + const peerDependencies = [ + '@hotwired/stimulus', + ...(packageData.peerDependencies ? Object.keys(packageData.peerDependencies) : []), + ]; + + inputFiles.forEach((file) => { + // custom handling for StimulusBundle + if (file.includes('StimulusBundle/assets/src/loader.ts')) { + peerDependencies.push('./controllers.js'); + } + + // React, Vue + if (file.includes('assets/src/loader.ts')) { + peerDependencies.push('./components.js'); + } + }); + + const outDir = path.join(packageRoot, 'dist'); + + return { + input: inputFiles, + output: { + dir: outDir, + entryFileNames: '[name].js', + format: 'esm', + }, + external: peerDependencies, + plugins: [ + resolve(), + typescript({ + filterRoot: '.', + tsconfig: path.join(__dirname, '..', 'tsconfig.json'), + include: [ + 'src/**/*.ts', + // TODO: Remove for the next major release + // "@rollup/plugin-typescript" v11.0.0 fixed an issue (https://github.com/rollup/plugins/pull/1310) that + // cause a breaking change for UX React users, the dist file requires "react-dom/client" instead of "react-dom" + // and it will break for users using the Symfony AssetMapper without Symfony Flex (for automatic "importmap.php" upgrade). + '**/node_modules/react-dom/client.js', + ], + compilerOptions: { + outDir: outDir, + declaration: true, + emitDeclarationOnly: true, + }, + }), + commonjs(), + wildcardExternalsPlugin(peerDependencies), + moveTypescriptDeclarationsPlugin(packageRoot), + ], + }; +} + +module.exports = { + getRollupConfiguration, +}; diff --git a/package.json b/package.json index e117c5a1c9c..57c927a2857 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,12 @@ "src/*/src/Bridge/*/assets" ], "scripts": { - "build": "node bin/build_javascript.js && node bin/build_styles.js", + "build": "yarn workspaces foreach -Apt run build", "test": "bin/run-vitest-all.sh", - "lint": "yarn workspaces foreach --all -pt run lint", - "format": "yarn workspaces foreach --all -pt run format", - "check-lint": "yarn workspaces foreach --all -pt run check-lint", - "check-format": "yarn workspaces foreach --all -pt run check-format" + "lint": "yarn workspaces foreach -Apt run lint", + "format": "yarn workspaces foreach -Apt run format", + "check-lint": "yarn workspaces foreach -Apt run check-lint", + "check-format": "yarn workspaces foreach -Apt run check-format" }, "devDependencies": { "@babel/core": "^7.25.2", @@ -24,7 +24,7 @@ "@rollup/plugin-typescript": "^11.1.6", "@symfony/stimulus-testing": "^2.0.1", "@vitest/browser": "^2.1.1", - "clean-css-cli": "^5.6.2", + "clean-css": "^5.3.3", "playwright": "^1.47.0", "rollup": "^4.22.5", "tslib": "^2.6.3", diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index 7ab3b404f8b..00000000000 --- a/rollup.config.js +++ /dev/null @@ -1,115 +0,0 @@ -const resolve = require('@rollup/plugin-node-resolve'); -const commonjs = require('@rollup/plugin-commonjs'); -const typescript = require('@rollup/plugin-typescript'); -const fs = require('fs'); -const glob = require('glob'); -const path = require('path'); - -/** - * Guarantees that any files imported from a peer dependency are treated as an external. - * - * For example, if we import `chart.js/auto`, that would not normally - * match the "chart.js" we pass to the "externals" config. This plugin - * catches that case and adds it as an external. - * - * Inspired by https://github.com/oat-sa/rollup-plugin-wildcard-external - */ -const wildcardExternalsPlugin = (peerDependencies) => ({ - name: 'wildcard-externals', - resolveId(source, importer) { - if (importer) { - let matchesExternal = false; - peerDependencies.forEach((peerDependency) => { - if (source.includes(`/${peerDependency}/`)) { - matchesExternal = true; - } - }); - - if (matchesExternal) { - return { - id: source, - external: true, - moduleSideEffects: true - }; - } - } - - return null; // other ids should be handled as usually - } -}); - -/** - * Moves the generated TypeScript declaration files to the correct location. - * - * This could probably be configured in the TypeScript plugin. - */ -const moveTypescriptDeclarationsPlugin = (packagePath) => ({ - name: 'move-ts-declarations', - writeBundle: async () => { - const isBridge = packagePath.includes('src/Bridge'); - const globPattern = isBridge - ? path.join(packagePath, 'dist', packagePath.replace(/^src\//, ''), '**/*.d.ts') - : path.join(packagePath, 'dist', '*', 'assets', 'src', '**/*.d.ts') - const files = glob.sync(globPattern); - files.forEach((file) => { - // a bit odd, but remove first 7 or 13 directories, which will leave - // only the relative path to the file - const relativePath = file.split('/').slice(isBridge ? 13 : 7).join('/'); - - const targetFile = path.join(packagePath, 'dist', relativePath); - if (!fs.existsSync(path.dirname(targetFile))) { - fs.mkdirSync(path.dirname(targetFile), { recursive: true }); - } - fs.renameSync(file, targetFile); - }); - } -}); - -const file = process.env.INPUT_FILE; -const packageRoot = path.join(file, '..', '..'); -const packagePath = path.join(packageRoot, 'package.json'); -const packageData = JSON.parse(fs.readFileSync(packagePath, 'utf8')); -const peerDependencies = [ - '@hotwired/stimulus', - ...(packageData.peerDependencies ? Object.keys(packageData.peerDependencies) : []) -]; - -// custom handling for StimulusBundle -if (file.includes('StimulusBundle/assets/src/loader.ts')) { - peerDependencies.push('./controllers.js'); -} -// React, Vue -if (file.includes('assets/src/loader.ts')) { - peerDependencies.push('./components.js'); -} - -module.exports = { - input: file, - output: { - file: path.join(packageRoot, 'dist', path.basename(file, '.ts') + '.js'), - format: 'esm', - }, - external: peerDependencies, - plugins: [ - resolve(), - typescript({ - filterRoot: packageRoot, - include: [ - 'src/**/*.ts', - // TODO: Remove for the next major release - // "@rollup/plugin-typescript" v11.0.0 fixed an issue (https://github.com/rollup/plugins/pull/1310) that - // cause a breaking change for UX React users, the dist file requires "react-dom/client" instead of "react-dom" - // and it will break for users using the Symfony AssetMapper without Symfony Flex (for automatic "importmap.php" upgrade). - '**/node_modules/react-dom/client.js' - ], - compilerOptions: { - outDir: '.', - declaration: true, - emitDeclarationOnly: true, - } - }), - commonjs(), - wildcardExternalsPlugin(peerDependencies), - moveTypescriptDeclarationsPlugin(packageRoot), - ], -}; diff --git a/src/Autocomplete/assets/package.json b/src/Autocomplete/assets/package.json index 204fb438d9c..bc6e9f1bd6c 100644 --- a/src/Autocomplete/assets/package.json +++ b/src/Autocomplete/assets/package.json @@ -6,7 +6,8 @@ "version": "1.0.0", "license": "MIT", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Chartjs/assets/package.json b/src/Chartjs/assets/package.json index 3b067838de0..b73c870c997 100644 --- a/src/Chartjs/assets/package.json +++ b/src/Chartjs/assets/package.json @@ -7,7 +7,8 @@ "main": "dist/controller.js", "types": "dist/controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Cropperjs/assets/package.json b/src/Cropperjs/assets/package.json index ae59f6c36e7..b22dfb50009 100644 --- a/src/Cropperjs/assets/package.json +++ b/src/Cropperjs/assets/package.json @@ -9,7 +9,8 @@ "css_source": "src/style.css" }, "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Dropzone/assets/package.json b/src/Dropzone/assets/package.json index ce35745715e..0ba33dd23a9 100644 --- a/src/Dropzone/assets/package.json +++ b/src/Dropzone/assets/package.json @@ -9,7 +9,8 @@ "css_source": "src/style.css" }, "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/LazyImage/assets/package.json b/src/LazyImage/assets/package.json index ddee00a915b..2d54ca5df1d 100644 --- a/src/LazyImage/assets/package.json +++ b/src/LazyImage/assets/package.json @@ -6,7 +6,8 @@ "main": "dist/controller.js", "types": "dist/controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/LiveComponent/assets/dist/Component/plugins/QueryStringPluging.d.ts b/src/LiveComponent/assets/dist/Component/plugins/QueryStringPluging.d.ts deleted file mode 100644 index 6f9feeeda3b..00000000000 --- a/src/LiveComponent/assets/dist/Component/plugins/QueryStringPluging.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Component from '../index'; -import { PluginInterface } from './PluginInterface'; -export default class implements PluginInterface { - private element; - private mapping; - attachToComponent(component: Component): void; - private registerBindings; - private updateUrl; -} diff --git a/src/LiveComponent/assets/package.json b/src/LiveComponent/assets/package.json index 0824d49b1a1..2702054189e 100644 --- a/src/LiveComponent/assets/package.json +++ b/src/LiveComponent/assets/package.json @@ -9,7 +9,8 @@ }, "license": "MIT", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Map/assets/package.json b/src/Map/assets/package.json index 4183d52794d..0c19eb28063 100644 --- a/src/Map/assets/package.json +++ b/src/Map/assets/package.json @@ -7,7 +7,8 @@ "main": "dist/abstract_map_controller.js", "types": "dist/abstract_map_controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Map/src/Bridge/Google/assets/package.json b/src/Map/src/Bridge/Google/assets/package.json index d753fd25211..aa1adfcd45e 100644 --- a/src/Map/src/Bridge/Google/assets/package.json +++ b/src/Map/src/Bridge/Google/assets/package.json @@ -7,7 +7,8 @@ "main": "dist/map_controller.js", "types": "dist/map_controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../../../../bin/build_package.js .", + "watch": "node ../../../../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Map/src/Bridge/Leaflet/assets/package.json b/src/Map/src/Bridge/Leaflet/assets/package.json index 496dad23ae0..fad8993e922 100644 --- a/src/Map/src/Bridge/Leaflet/assets/package.json +++ b/src/Map/src/Bridge/Leaflet/assets/package.json @@ -7,7 +7,8 @@ "main": "dist/map_controller.js", "types": "dist/map_controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../../../../bin/build_package.js .", + "watch": "node ../../../../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Notify/assets/package.json b/src/Notify/assets/package.json index 10b05cb2768..92df45db303 100644 --- a/src/Notify/assets/package.json +++ b/src/Notify/assets/package.json @@ -6,7 +6,8 @@ "main": "dist/controller.js", "types": "dist/controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/React/assets/package.json b/src/React/assets/package.json index ba9ba75ca7a..6458605da15 100644 --- a/src/React/assets/package.json +++ b/src/React/assets/package.json @@ -6,7 +6,8 @@ "main": "dist/register_controller.js", "types": "dist/register_controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/StimulusBundle/assets/package.json b/src/StimulusBundle/assets/package.json index 11022825165..00e520bd602 100644 --- a/src/StimulusBundle/assets/package.json +++ b/src/StimulusBundle/assets/package.json @@ -5,7 +5,8 @@ "license": "MIT", "main": "dist/loader.js", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Svelte/assets/package.json b/src/Svelte/assets/package.json index aff845fe83f..0e5731a1097 100644 --- a/src/Svelte/assets/package.json +++ b/src/Svelte/assets/package.json @@ -5,7 +5,8 @@ "version": "1.0.0", "license": "MIT", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Swup/assets/package.json b/src/Swup/assets/package.json index 03b574b2c94..f03935eb02f 100644 --- a/src/Swup/assets/package.json +++ b/src/Swup/assets/package.json @@ -6,7 +6,8 @@ "main": "dist/controller.js", "types": "dist/controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/TogglePassword/assets/package.json b/src/TogglePassword/assets/package.json index 1ea4193c111..7811e54b561 100644 --- a/src/TogglePassword/assets/package.json +++ b/src/TogglePassword/assets/package.json @@ -9,7 +9,8 @@ "css_source": "src/style.css" }, "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Translator/assets/package.json b/src/Translator/assets/package.json index 19cd6d4a38e..cb01308fb5c 100644 --- a/src/Translator/assets/package.json +++ b/src/Translator/assets/package.json @@ -6,7 +6,8 @@ "main": "dist/translator_controller.js", "types": "dist/translator_controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Turbo/assets/package.json b/src/Turbo/assets/package.json index a7c323227c9..570a487d247 100644 --- a/src/Turbo/assets/package.json +++ b/src/Turbo/assets/package.json @@ -7,7 +7,8 @@ "main": "dist/turbo_controller.js", "types": "dist/turbo_controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Typed/assets/package.json b/src/Typed/assets/package.json index 526f36b2592..f0e83265f6f 100644 --- a/src/Typed/assets/package.json +++ b/src/Typed/assets/package.json @@ -6,7 +6,8 @@ "main": "dist/controller.js", "types": "dist/controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/src/Vue/assets/package.json b/src/Vue/assets/package.json index 31f53b93d2e..61d381247be 100644 --- a/src/Vue/assets/package.json +++ b/src/Vue/assets/package.json @@ -6,7 +6,8 @@ "main": "dist/register_controller.js", "types": "dist/register_controller.d.ts", "scripts": { - "build": "echo 'The build script is not yet configured.' && exit 1", + "build": "node ../../../bin/build_package.js .", + "watch": "node ../../../bin/build_package.js . --watch", "test": "echo 'The test script is not yet configured.' && exit 1", "lint": "biome lint --write", "format": "biome format --write", diff --git a/yarn.lock b/yarn.lock index a40a02fcb94..27e8d369234 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3879,7 +3879,7 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": +"anymatch@npm:^3.0.3": version: 3.1.3 resolution: "anymatch@npm:3.1.3" dependencies: @@ -4135,13 +4135,6 @@ __metadata: languageName: node linkType: hard -"binary-extensions@npm:^2.0.0": - version: 2.2.0 - resolution: "binary-extensions@npm:2.2.0" - checksum: 10c0/d73d8b897238a2d3ffa5f59c0241870043aa7471335e89ea5e1ff48edb7c2d0bb471517a3e4c5c3f4c043615caa2717b5f80a5e61e07503d51dc85cb848e665d - languageName: node - linkType: hard - "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -4179,7 +4172,7 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.2, braces@npm:~3.0.2": +"braces@npm:^3.0.2": version: 3.0.2 resolution: "braces@npm:3.0.2" dependencies: @@ -4390,25 +4383,6 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^3.5.2": - version: 3.5.3 - resolution: "chokidar@npm:3.5.3" - dependencies: - anymatch: "npm:~3.1.2" - braces: "npm:~3.0.2" - fsevents: "npm:~2.3.2" - glob-parent: "npm:~5.1.2" - is-binary-path: "npm:~2.1.0" - is-glob: "npm:~4.0.1" - normalize-path: "npm:~3.0.0" - readdirp: "npm:~3.6.0" - dependenciesMeta: - fsevents: - optional: true - checksum: 10c0/1076953093e0707c882a92c66c0f56ba6187831aa51bb4de878c1fec59ae611a3bf02898f190efec8e77a086b8df61c2b2a3ea324642a0558bdf8ee6c5dc9ca1 - languageName: node - linkType: hard - "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" @@ -4449,26 +4423,12 @@ __metadata: languageName: node linkType: hard -"clean-css-cli@npm:^5.6.2": - version: 5.6.2 - resolution: "clean-css-cli@npm:5.6.2" - dependencies: - chokidar: "npm:^3.5.2" - clean-css: "npm:^5.3.2" - commander: "npm:7.x" - glob: "npm:^7.1.6" - bin: - cleancss: bin/cleancss - checksum: 10c0/125d6aa8d34bce0598bcca2a14ca0c5f33dfcb237de28770c7982888d978070efd5bb5007d4d7a89c7cca385b5ed7d2717fa64e6f4a91a47cacf85b7522babd7 - languageName: node - linkType: hard - -"clean-css@npm:^5.3.2": - version: 5.3.2 - resolution: "clean-css@npm:5.3.2" +"clean-css@npm:^5.3.3": + version: 5.3.3 + resolution: "clean-css@npm:5.3.3" dependencies: source-map: "npm:~0.6.0" - checksum: 10c0/315e0e81306524bd2c1905fa6823bf7658be40799b78f446e5e6922808718d2b80266fb3e96842a06176fa683bc2c1a0d2827b08d154e2f9cf136d7bda909d33 + checksum: 10c0/381de7523e23f3762eb180e327dcc0cedafaf8cb1cd8c26b7cc1fc56e0829a92e734729c4f955394d65ed72fb62f82d8baf78af34b33b8a7d41ebad2accdd6fb languageName: node linkType: hard @@ -4593,13 +4553,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:7.x": - version: 7.2.0 - resolution: "commander@npm:7.2.0" - checksum: 10c0/8d690ff13b0356df7e0ebbe6c59b4712f754f4b724d4f473d3cc5b3fdcf978e3a5dc3078717858a2ceb50b0f84d0660a7f22a96cdc50fb877d0c9bb31593d23a - languageName: node - linkType: hard - "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" @@ -5637,15 +5590,6 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:~5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee - languageName: node - linkType: hard - "glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -5662,7 +5606,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -6048,15 +5992,6 @@ __metadata: languageName: node linkType: hard -"is-binary-path@npm:~2.1.0": - version: 2.1.0 - resolution: "is-binary-path@npm:2.1.0" - dependencies: - binary-extensions: "npm:^2.0.0" - checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 - languageName: node - linkType: hard - "is-boolean-object@npm:^1.1.0": version: 1.1.2 resolution: "is-boolean-object@npm:1.1.2" @@ -6175,13 +6110,6 @@ __metadata: languageName: node linkType: hard -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -6196,15 +6124,6 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^4.0.1, is-glob@npm:~4.0.1": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a - languageName: node - linkType: hard - "is-lambda@npm:^1.0.1": version: 1.0.1 resolution: "is-lambda@npm:1.0.1" @@ -7843,7 +7762,7 @@ __metadata: languageName: node linkType: hard -"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": +"normalize-path@npm:^3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 @@ -8160,7 +8079,7 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be @@ -8406,15 +8325,6 @@ __metadata: languageName: node linkType: hard -"readdirp@npm:~3.6.0": - version: 3.6.0 - resolution: "readdirp@npm:3.6.0" - dependencies: - picomatch: "npm:^2.2.1" - checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b - languageName: node - linkType: hard - "redent@npm:^3.0.0": version: 3.0.0 resolution: "redent@npm:3.0.0" @@ -8773,7 +8683,7 @@ __metadata: "@rollup/plugin-typescript": "npm:^11.1.6" "@symfony/stimulus-testing": "npm:^2.0.1" "@vitest/browser": "npm:^2.1.1" - clean-css-cli: "npm:^5.6.2" + clean-css: "npm:^5.3.3" playwright: "npm:^1.47.0" rollup: "npm:^4.22.5" tslib: "npm:^2.6.3" From bc1d63cd9c046528e1c9c78ee8ce69cbd257015f Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sat, 2 Nov 2024 15:31:37 +0100 Subject: [PATCH 06/42] [DX] Reconfigure lint/format tasks to not run the command for each workspace, since Biome is super fast (also include bin and test JS files) --- bin/build_package.js | 46 ++++++++++++++++++++++---------------------- bin/rollup.js | 23 +++++++++++++--------- biome.json | 2 ++ package.json | 8 ++++---- test/setup.js | 2 -- 5 files changed, 43 insertions(+), 38 deletions(-) diff --git a/bin/build_package.js b/bin/build_package.js index 74be88a9c21..ee3054d253d 100644 --- a/bin/build_package.js +++ b/bin/build_package.js @@ -38,12 +38,11 @@ async function main() { const srcDir = path.join(packageRoot, 'src'); const distDir = path.join(packageRoot, 'dist'); - if (!fs.existsSync(srcDir)) { console.error(`The package directory "${packageRoot}" does not contain a "src" directory.`); process.exit(1); } - + if (fs.existsSync(distDir)) { console.log(`Cleaning up the "${distDir}" directory...`); await fs.promises.rm(distDir, { recursive: true }); @@ -53,41 +52,42 @@ async function main() { const inputScriptFiles = [ ...glob.sync(path.join(srcDir, '*controller.ts')), ...(['@symfony/ux-react', '@symfony/ux-vue', '@symfony/ux-svelte'].includes(packageName) - ? [ - path.join(srcDir, 'loader.ts'), - path.join(srcDir, 'components.ts'), - ] + ? [path.join(srcDir, 'loader.ts'), path.join(srcDir, 'components.ts')] : []), ...(packageName === '@symfony/stimulus-bundle' - ? [ - path.join(srcDir, 'loader.ts'), - path.join(srcDir, 'controllers.ts'), - ] : []), + ? [path.join(srcDir, 'loader.ts'), path.join(srcDir, 'controllers.ts')] + : []), ]; - - const inputStyleFile = packageData.config && packageData.config.css_source; + + const inputStyleFile = packageData.config?.css_source; const buildCss = async () => { - const inputStyleFileDist = inputStyleFile ? path.resolve(distDir, `${path.basename(inputStyleFile, '.css')}.min.css`) : undefined; + const inputStyleFileDist = inputStyleFile + ? path.resolve(distDir, `${path.basename(inputStyleFile, '.css')}.min.css`) + : undefined; if (!inputStyleFile) { return; } - + console.log('Minifying CSS...'); const css = await fs.promises.readFile(inputStyleFile, 'utf-8'); const minified = new CleanCSS().minify(css).styles; await fs.promises.writeFile(inputStyleFileDist, minified); - } + }; if (inputScriptFiles.length === 0) { - console.error(`No input files found for package "${packageName}" (directory "${packageRoot}").\nEnsure you have at least a file matching the pattern "src/*_controller.ts", or manually specify input files in "${__filename}" file.`); + console.error( + `No input files found for package "${packageName}" (directory "${packageRoot}").\nEnsure you have at least a file matching the pattern "src/*_controller.ts", or manually specify input files in "${__filename}" file.` + ); process.exit(1); } const rollupConfig = getRollupConfiguration({ packageRoot, inputFiles: inputScriptFiles }); if (args.values.watch) { - console.log(`Watching for JavaScript${inputStyleFile ? ' and CSS' : ''} files modifications in "${srcDir}" directory...`); - + console.log( + `Watching for JavaScript${inputStyleFile ? ' and CSS' : ''} files modifications in "${srcDir}" directory...` + ); + if (inputStyleFile) { rollupConfig.plugins = (rollupConfig.plugins || []).concat({ name: 'watcher', @@ -96,7 +96,7 @@ async function main() { }, }); } - + const watcher = rollup.watch(rollupConfig); watcher.on('event', ({ result }) => { if (result) { @@ -105,7 +105,7 @@ async function main() { }); watcher.on('change', async (id, { event }) => { if (event === 'update') { - console.log(`Files were modified, rebuilding...`); + console.log('Files were modified, rebuilding...'); } if (inputStyleFile && id === inputStyleFile) { @@ -115,12 +115,12 @@ async function main() { } else { console.log(`Building JavaScript files from ${packageName} package...`); const start = Date.now(); - + const bundle = await rollup.rollup(rollupConfig); await bundle.write(rollupConfig.output); - + await buildCss(); - + console.log(`Done in ${((Date.now() - start) / 1000).toFixed(3)} seconds.`); } } diff --git a/bin/rollup.js b/bin/rollup.js index b3670dd98aa..a75c3036143 100644 --- a/bin/rollup.js +++ b/bin/rollup.js @@ -1,9 +1,9 @@ +const fs = require('node:fs'); +const path = require('node:path'); const resolve = require('@rollup/plugin-node-resolve'); const commonjs = require('@rollup/plugin-commonjs'); const typescript = require('@rollup/plugin-typescript'); -const fs = require('fs'); const glob = require('glob'); -const path = require('path'); /** * Guarantees that any files imported from a peer dependency are treated as an external. @@ -54,10 +54,15 @@ const moveTypescriptDeclarationsPlugin = (packageRoot) => ({ const relativePath = file; // a bit odd, but remove first 7 or 4 directories, which will leave only the relative path to the file // ex: dist/Chartjs/assets/src/controller.d.ts' => 'dist/controller.d.ts' - const targetFile = relativePath.replace(relativePath.split('/').slice(1, isBridge ? 7 : 4).join('/') + '/', ''); - + const targetFile = relativePath.replace( + `${relativePath + .split('/') + .slice(1, isBridge ? 7 : 4) + .join('/')}/`, + '' + ); if (!fs.existsSync(path.dirname(targetFile))) { - fs.mkdirSync(path.dirname(targetFile), { recursive: true }); + fs.mkdirSync(path.dirname(targetFile), { recursive: true }); } fs.renameSync(file, targetFile); }); @@ -81,15 +86,15 @@ function getRollupConfiguration({ packageRoot, inputFiles }) { if (file.includes('StimulusBundle/assets/src/loader.ts')) { peerDependencies.push('./controllers.js'); } - + // React, Vue if (file.includes('assets/src/loader.ts')) { peerDependencies.push('./components.js'); } }); - + const outDir = path.join(packageRoot, 'dist'); - + return { input: inputFiles, output: { @@ -106,7 +111,7 @@ function getRollupConfiguration({ packageRoot, inputFiles }) { include: [ 'src/**/*.ts', // TODO: Remove for the next major release - // "@rollup/plugin-typescript" v11.0.0 fixed an issue (https://github.com/rollup/plugins/pull/1310) that + // "@rollup/plugin-typescript" v11.0.0 fixed an issue (https://github.com/rollup/plugins/pull/1310) that // cause a breaking change for UX React users, the dist file requires "react-dom/client" instead of "react-dom" // and it will break for users using the Symfony AssetMapper without Symfony Flex (for automatic "importmap.php" upgrade). '**/node_modules/react-dom/client.js', diff --git a/biome.json b/biome.json index a4f7f0f3430..c1cf1792e3b 100644 --- a/biome.json +++ b/biome.json @@ -4,6 +4,8 @@ "include": [ "*.json", "*.md", + "bin/*.js", + "test/*.js", "src/*/*.json", "src/*/*/md", "src/*/assets/src/**", diff --git a/package.json b/package.json index 57c927a2857..dbba6fd6c58 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "scripts": { "build": "yarn workspaces foreach -Apt run build", "test": "bin/run-vitest-all.sh", - "lint": "yarn workspaces foreach -Apt run lint", - "format": "yarn workspaces foreach -Apt run format", - "check-lint": "yarn workspaces foreach -Apt run check-lint", - "check-format": "yarn workspaces foreach -Apt run check-format" + "lint": "biome lint --write", + "format": "biome format --write", + "check-lint": "biome lint", + "check-format": "biome format" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/test/setup.js b/test/setup.js index ddd4655c30e..f60ad9b03e4 100644 --- a/test/setup.js +++ b/test/setup.js @@ -7,6 +7,4 @@ * file that was distributed with this source code. */ -'use strict'; - import '@symfony/stimulus-testing/setup'; From 8397b52530dbe8e4f031d36ce6a9cd0b6d111442 Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sat, 2 Nov 2024 17:22:11 +0100 Subject: [PATCH 07/42] [DX] Rework testing process, add `test` script to packages package.json --- bin/{run-vitest-all.sh => test_package.sh} | 51 ++++++++++++------- package.json | 2 +- src/Autocomplete/assets/package.json | 2 +- src/Chartjs/assets/package.json | 2 +- src/Cropperjs/assets/package.json | 2 +- src/Dropzone/assets/package.json | 2 +- src/LazyImage/assets/package.json | 2 +- src/LiveComponent/assets/package.json | 2 +- src/Map/assets/package.json | 2 +- src/Map/src/Bridge/Google/assets/package.json | 2 +- .../src/Bridge/Leaflet/assets/package.json | 2 +- src/Notify/assets/package.json | 2 +- src/React/assets/package.json | 2 +- src/StimulusBundle/assets/package.json | 2 +- src/Svelte/assets/package.json | 2 +- src/Swup/assets/package.json | 2 +- src/TogglePassword/assets/package.json | 2 +- src/Translator/assets/package.json | 2 +- src/Turbo/assets/package.json | 2 +- src/Typed/assets/package.json | 2 +- src/Vue/assets/package.json | 2 +- 21 files changed, 52 insertions(+), 39 deletions(-) rename bin/{run-vitest-all.sh => test_package.sh} (66%) diff --git a/bin/run-vitest-all.sh b/bin/test_package.sh similarity index 66% rename from bin/run-vitest-all.sh rename to bin/test_package.sh index 74db629be6c..669e293c949 100755 --- a/bin/run-vitest-all.sh +++ b/bin/test_package.sh @@ -1,8 +1,20 @@ #!/bin/bash +# This script is used to test an UX package. +# It also handle the case where a package has multiple versions of a peerDependency defined. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +PROJECT_DIR=$(dirname "$SCRIPT_DIR") + # Flag to track if any test fails all_tests_passed=true +# Check if we have at least one argument +if [ $# -eq 0 ] + then + echo "No arguments supplied, please provide the package's path." +fi + # Check if jq is installed if ! command -v jq &> /dev/null; then echo "jq is required but not installed. Aborting." @@ -11,16 +23,31 @@ fi runTestSuite() { echo -e "Running tests for $workspace...\n" - yarn workspace $workspace run -T vitest --run || { all_tests_passed=false; } + yarn run -T vitest --run || { all_tests_passed=false; } } processWorkspace() { - local workspace="$1" - local location="$2" + local location="$1" - echo -e "Processing workspace $workspace at location $location...\n" + if [ ! -d "$location" ]; then + echo "No directory found at $location" + return + fi package_json_path="$location/package.json" + if [ ! -f "$package_json_path" ]; then + echo "No package.json found at $package_json_path" + return + fi + + workspace=$(jq -r '.name' "$package_json_path") + if [ -z "$workspace" ]; then + echo "No name found in package.json at $package_json_path" + return + fi + + echo -e "Processing workspace $workspace at location $location...\n" + echo "Checking '$package_json_path' for peerDependencies with multiple versions defined" deps_with_multiple_versions=$(jq -r '.peerDependencies | to_entries[] | select(.value | contains("||")) | .key' "$package_json_path") @@ -48,21 +75,7 @@ processWorkspace() { fi } -# Iterate over each workspace using process substitution -while IFS= read -r workspace_info; do - # Split the workspace_info into workspace and location - workspace=$(echo "$workspace_info" | jq -r '.name') - location=$(echo "$workspace_info" | jq -r '.location') - - # Skip the root workspace - if [ $workspace == "null" ]; then - continue - fi - - # Call the function to process the workspace - processWorkspace "$workspace" "$location" - -done < <(yarn workspaces list --json) +processWorkspace "$(realpath "$PWD/$1")" # Check the flag at the end and exit with code 1 if any test failed if [ "$all_tests_passed" = false ]; then diff --git a/package.json b/package.json index dbba6fd6c58..0952bdd9d58 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ ], "scripts": { "build": "yarn workspaces foreach -Apt run build", - "test": "bin/run-vitest-all.sh", + "test": "yarn workspaces foreach -Apt run test", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Autocomplete/assets/package.json b/src/Autocomplete/assets/package.json index bc6e9f1bd6c..a7a238c50f2 100644 --- a/src/Autocomplete/assets/package.json +++ b/src/Autocomplete/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Chartjs/assets/package.json b/src/Chartjs/assets/package.json index b73c870c997..bfbab3f8cf5 100644 --- a/src/Chartjs/assets/package.json +++ b/src/Chartjs/assets/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Cropperjs/assets/package.json b/src/Cropperjs/assets/package.json index b22dfb50009..ee4b4e29c57 100644 --- a/src/Cropperjs/assets/package.json +++ b/src/Cropperjs/assets/package.json @@ -11,7 +11,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Dropzone/assets/package.json b/src/Dropzone/assets/package.json index 0ba33dd23a9..03c23dca910 100644 --- a/src/Dropzone/assets/package.json +++ b/src/Dropzone/assets/package.json @@ -11,7 +11,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/LazyImage/assets/package.json b/src/LazyImage/assets/package.json index 2d54ca5df1d..7f2c8d854f8 100644 --- a/src/LazyImage/assets/package.json +++ b/src/LazyImage/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/LiveComponent/assets/package.json b/src/LiveComponent/assets/package.json index 2702054189e..8e5ece78f03 100644 --- a/src/LiveComponent/assets/package.json +++ b/src/LiveComponent/assets/package.json @@ -11,7 +11,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Map/assets/package.json b/src/Map/assets/package.json index 0c19eb28063..69ebc71be99 100644 --- a/src/Map/assets/package.json +++ b/src/Map/assets/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Map/src/Bridge/Google/assets/package.json b/src/Map/src/Bridge/Google/assets/package.json index aa1adfcd45e..17322cf9241 100644 --- a/src/Map/src/Bridge/Google/assets/package.json +++ b/src/Map/src/Bridge/Google/assets/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "node ../../../../../../bin/build_package.js .", "watch": "node ../../../../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Map/src/Bridge/Leaflet/assets/package.json b/src/Map/src/Bridge/Leaflet/assets/package.json index fad8993e922..1ac16b1d8f0 100644 --- a/src/Map/src/Bridge/Leaflet/assets/package.json +++ b/src/Map/src/Bridge/Leaflet/assets/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "node ../../../../../../bin/build_package.js .", "watch": "node ../../../../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Notify/assets/package.json b/src/Notify/assets/package.json index 92df45db303..37c98d79fc2 100644 --- a/src/Notify/assets/package.json +++ b/src/Notify/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/React/assets/package.json b/src/React/assets/package.json index 6458605da15..8f1b3d50f68 100644 --- a/src/React/assets/package.json +++ b/src/React/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/StimulusBundle/assets/package.json b/src/StimulusBundle/assets/package.json index 00e520bd602..4d0d2b401e9 100644 --- a/src/StimulusBundle/assets/package.json +++ b/src/StimulusBundle/assets/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Svelte/assets/package.json b/src/Svelte/assets/package.json index 0e5731a1097..7b80877f22f 100644 --- a/src/Svelte/assets/package.json +++ b/src/Svelte/assets/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Swup/assets/package.json b/src/Swup/assets/package.json index f03935eb02f..1cabd23f7ca 100644 --- a/src/Swup/assets/package.json +++ b/src/Swup/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/TogglePassword/assets/package.json b/src/TogglePassword/assets/package.json index 7811e54b561..2e27fec2313 100644 --- a/src/TogglePassword/assets/package.json +++ b/src/TogglePassword/assets/package.json @@ -11,7 +11,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Translator/assets/package.json b/src/Translator/assets/package.json index cb01308fb5c..6fd84918fb8 100644 --- a/src/Translator/assets/package.json +++ b/src/Translator/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Turbo/assets/package.json b/src/Turbo/assets/package.json index 570a487d247..bf086784874 100644 --- a/src/Turbo/assets/package.json +++ b/src/Turbo/assets/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Typed/assets/package.json b/src/Typed/assets/package.json index f0e83265f6f..d146fb639f9 100644 --- a/src/Typed/assets/package.json +++ b/src/Typed/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", diff --git a/src/Vue/assets/package.json b/src/Vue/assets/package.json index 61d381247be..9b20a09f8af 100644 --- a/src/Vue/assets/package.json +++ b/src/Vue/assets/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "node ../../../bin/build_package.js .", "watch": "node ../../../bin/build_package.js . --watch", - "test": "echo 'The test script is not yet configured.' && exit 1", + "test": "../../../bin/test_package.sh .", "lint": "biome lint --write", "format": "biome format --write", "check-lint": "biome lint", From b8dc5fd57953b64c9807fe6ad7a8daaf3422ccd5 Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sun, 3 Nov 2024 00:00:49 +0100 Subject: [PATCH 08/42] Ignore `var` folder in Biome.js --- biome.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biome.json b/biome.json index c1cf1792e3b..36d42169ba6 100644 --- a/biome.json +++ b/biome.json @@ -15,7 +15,7 @@ "src/*/src/Bridge/*/assets/src/**", "src/*/src/Bridge/*/assets/test/**" ], - "ignore": ["**/composer.json", "**/vendor", "**/package.json", "**/node_modules"] + "ignore": ["**/composer.json", "**/vendor", "**/package.json", "**/node_modules", "**/var"] }, "linter": { "rules": { From de4d99cb1225250e4064a226aa1b4b543f96d503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sun, 3 Nov 2024 00:01:58 +0100 Subject: [PATCH 09/42] [Site] Use variable webfont Source: https://github.com/canonical/Ubuntu-Sans-fonts Credits: https://design.ubuntu.com/font --- ux.symfony.com/assets/styles/app/_font.scss | 14 ++++++++++++++ ux.symfony.com/assets/styles/app/_root.scss | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ux.symfony.com/assets/styles/app/_font.scss b/ux.symfony.com/assets/styles/app/_font.scss index 2228540884a..8430dad7d18 100644 --- a/ux.symfony.com/assets/styles/app/_font.scss +++ b/ux.symfony.com/assets/styles/app/_font.scss @@ -20,3 +20,17 @@ url("https://cdn.jsdelivr.net/npm/@fontsource/ubuntu@5.0.8/files/ubuntu-latin-700-normal.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } +/* ubuntu-sans-latin-wght-normal */ +@font-face { + font-family: 'Ubuntu Sans'; + font-style: normal; + font-display: swap; + font-weight: 100 800; + src: local("Ubuntu Sans"), + local("Ubuntu-Sans"), + local("Ubuntu-Sans-Variable"), + local("UbuntuSans"), + local("UbuntuSans-Variable"), + url(https://cdn.jsdelivr.net/fontsource/fonts/ubuntu-sans:vf@latest/latin-wght-normal.woff2) format('woff2-variations'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/ux.symfony.com/assets/styles/app/_root.scss b/ux.symfony.com/assets/styles/app/_root.scss index ba8fcd7af2b..9514471f1f0 100644 --- a/ux.symfony.com/assets/styles/app/_root.scss +++ b/ux.symfony.com/assets/styles/app/_root.scss @@ -14,7 +14,7 @@ --space-larger: 2rem; // Fonts - --font-family-title: "Ubuntu", "Helvetica Neue", sans-serif; + --font-family-title: "Ubuntu Sans", "Ubuntu", system-ui, sans-serif; --font-family-text: system-ui, sans-serif; --font-family-code: ui-monospace, "SF Mono", SFMono-Regular, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; From c6d4db634468f97a02694ce4880efcc2a9b8beaa Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sun, 13 Oct 2024 08:42:46 +0200 Subject: [PATCH 10/42] Add CI workflow to compute diff between files dist files --- .github/generate-dist-files-size-diff.mjs | 177 ++++++++++++++++++ .../dist-files-size-diff-comment.yaml | 22 +++ .github/workflows/dist-files-size-diff.yaml | 68 +++++++ 3 files changed, 267 insertions(+) create mode 100644 .github/generate-dist-files-size-diff.mjs create mode 100644 .github/workflows/dist-files-size-diff-comment.yaml create mode 100644 .github/workflows/dist-files-size-diff.yaml diff --git a/.github/generate-dist-files-size-diff.mjs b/.github/generate-dist-files-size-diff.mjs new file mode 100644 index 00000000000..fc909daf1a1 --- /dev/null +++ b/.github/generate-dist-files-size-diff.mjs @@ -0,0 +1,177 @@ +/** + * Generate a markdown table with the difference in size of the dist files between the base and the PR. + */ + +/* +Usage: +```shell +BASE_DIST_FILES='{"src/Autocomplete/assets/dist/controller.js":{"size":15382,"size_gz":3716},"src/Chartjs/assets/dist/controller.js":{"size":2281,"size_gz":771},"src/Cropperjs/assets/dist/controller.js":{"size":1044,"size_gz":475}}' \ +PR_DIST_FILES='{"src/Chartjs/assets/dist/controller.js":{"size":1281,"size_gz":171},"src/Cropperjs/assets/dist/controller.js":{"size":1044,"size_gz":475},"src/Cropperjs/assets/dist/style.min.css":{"size":32,"size_gz":66},"src/Dropzone/assets/dist/controller.js":{"size":3199,"size_gz":816},"src/Map/src/Bridge/Google/assets/dist/foo.js":{"size":3199,"size_gz":816}}' \ +GITHUB_REPOSITORY='symfony/ux' \ +GITHUB_HEAD_REF='my-branch-name' \ + node .github/generate-dist-files-size-diff.mjs +``` + */ + +if (!process.env.BASE_DIST_FILES) { + throw new Error('Missing or invalid "BASE_DIST_FILES" env variable.'); +} + +if (!process.env.PR_DIST_FILES) { + throw new Error('Missing or invalid "PR_DIST_FILES" env variable.'); +} + +if (!process.env.GITHUB_REPOSITORY) { + throw new Error('Missing or invalid "GITHUB_REPOSITORY" env variable.'); +} + +if (!process.env.GITHUB_HEAD_REF) { + throw new Error('Missing or invalid "GITHUB_HEAD_REF" env variable.'); +} + +/** + * Adapted from https://gist.github.com/zentala/1e6f72438796d74531803cc3833c039c?permalink_comment_id=4455218#gistcomment-4455218 + * @param {number} bytes + * @param {number} digits + * @returns {string} + */ +function formatBytes(bytes, digits = 2) { + if (bytes === 0) { + return '0 B'; + } + const sizes = [`B`, 'kB', 'MB']; + const i = Math.floor(Math.log(bytes) / Math.log(1024)); + + return parseFloat((bytes / Math.pow(1024, i)).toFixed(digits)) + ' ' + sizes[i]; +} + +/** + * @param {number} from + * @param {number} to + * @returns {number} + */ +function computeDiffPercent(from, to) { + if (from === to) { + return 0; + } + + return Math.round((from - to) / from * -100); +} + +/** + * @param {number} percent + * @returns {string} + */ +function formatDiffPercent(percent) { + return percent > 0 ? `+${percent}% πŸ“ˆ` : percent < 0 ? `${percent}% πŸ“‰` : `${percent}%`; +} + +export function main() { + const repoUrl = `https://github.com/${process.env.GITHUB_REPOSITORY}`; + /** @type {Record} */ + const base = JSON.parse(process.env.BASE_DIST_FILES); + /** @type {Record} */ + const pr = JSON.parse(process.env.PR_DIST_FILES); + let output = '

πŸ“Š Dist packagesFiles size difference

\n\n'; + + /** + * @type {Map + * }>} + */ + const packagesFiles = [...new Set([...Object.keys(pr), ...Object.keys(base)])] + .sort() + .reduce((acc, file) => { + const beforeSize = base[file]?.size || 0; + const afterSize = pr[file]?.size || 0; + const beforeSizeGz = base[file]?.size_gz || 0; + const afterSizeGz = pr[file]?.size_gz || 0; + + if (beforeSize !== afterSize) { + const isBridge = file.includes('src/Bridge'); // we assume that's enough for now + const packageName = file.split('/')[1]; + const bridgeName = isBridge ? file.split('/')[4] : ''; + const key = isBridge ? `${packageName} (Bridge ${bridgeName})` : packageName; + if (!acc.has(key)) { + acc.set(key, { + meta: { + packageName, + bridgeName, + url: isBridge ? `${repoUrl}/tree/${process.env.GITHUB_HEAD_REF}/src/${packageName}/src/Bridge/${bridgeName}/assets/dist` : `${repoUrl}/tree/${process.env.GITHUB_HEAD_REF}/src/${packageName}/assets/dist`, + }, files: new Set(), + }); + } + + const added = !base[file] && pr[file]; + const removed = base[file] && !pr[file]; + + acc.get(key).files.add({ + state: added ? 'added' : (removed ? 'removed' : 'changed'), + before: { size: beforeSize, sizeGz: beforeSizeGz }, + after: { size: afterSize, sizeGz: afterSizeGz }, + diffPercent: { + size: removed ? -100 : (added ? 100 : computeDiffPercent(beforeSize, afterSize)), + sizeGz: removed ? -100 : (added ? 100 : computeDiffPercent(beforeSizeGz, afterSizeGz)), + }, + meta: { + fileNameShort: file.replace(isBridge ? `src/${file.split('/')[1]}/src/Bridge/${file.split('/')[4]}/assets/dist/` : `src/${file.split('/')[1]}/assets/dist/`, ''), + fileNameUrl: `${repoUrl}/blob/${process.env.GITHUB_HEAD_REF}/${file}`, + }, + }); + } + + return acc; + }, new Map); + + if (packagesFiles.size === 0) { + output += 'ℹ️ No difference in dist packagesFiles.\n'; + return output; + } + + output += 'Thanks for the PR! Here is the difference in size of the dist packagesFiles between the base and the PR.\n'; + output += 'Please review the changes and make sure they are expected.\n\n'; + output += ` + + `; + for (const [pkgKey, pkg] of packagesFiles.entries()) { + output += ``; + for (const file of pkg.files) { + output += ` + + `; + output += file.state === 'added' + ? `` + : ``; + output += file.state === 'removed' + ? `` + : ``; + output += ``; + } + } + output += ` +
FileBefore (Size / Gzip)After (Size / Gzip)
${pkgKey}
${file.meta.fileNameShort}Added + ${formatBytes(file.before.size)} + / ${formatBytes(file.before.sizeGz)} + Removed + ${formatBytes(file.after.size)}${file.state === 'changed' ? `${formatDiffPercent(file.diffPercent.size)}` : ''} + / ${formatBytes(file.after.sizeGz)}${file.state === 'changed' ? `${formatDiffPercent(file.diffPercent.sizeGz)}` : ''} +
+`; + + return output; +} + +if (!process.env.CI) { + console.log(main()); +} diff --git a/.github/workflows/dist-files-size-diff-comment.yaml b/.github/workflows/dist-files-size-diff-comment.yaml new file mode 100644 index 00000000000..d43f79c0a74 --- /dev/null +++ b/.github/workflows/dist-files-size-diff-comment.yaml @@ -0,0 +1,22 @@ +name: Dist Files Size Diff (Comment) + +on: + workflow_run: + workflows: ["Dist Files Size Diff"] + types: + - completed + +jobs: + dist-files-size-diff: + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: dist-size-${{ github.event.number }} + + - name: Comment on the pull request (if success) + if: ${{ always() && steps.diff.conclusion == 'success' }} + uses: marocchino/sticky-pull-request-comment@v2 + with: + path: ./dist-size.md diff --git a/.github/workflows/dist-files-size-diff.yaml b/.github/workflows/dist-files-size-diff.yaml new file mode 100644 index 00000000000..b690047decc --- /dev/null +++ b/.github/workflows/dist-files-size-diff.yaml @@ -0,0 +1,68 @@ +name: Dist Files Size Diff + +on: + pull_request: + types: [opened, synchronize] + paths: + - 'src/*/assets/dist/**' + - 'src/*/src/Bridge/*/assets/dist/**' + +jobs: + dist-files-size-diff: + runs-on: ubuntu-latest + steps: + - name: Configure git + run: | + git config --global user.email "" + git config --global user.name "github-action[bot]" + + - uses: actions/checkout@v4 + with: + ref: ${{ github.base_ref }} + + - name: Get dist files size (from base branch) + id: base-dist-files + run: | + set -e + + FILES=$(find src -mindepth 2 -path '*/assets/dist/*' \( -name "*.js" -o -name "*.css" \) -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do + echo "{\"$file\": {\"size\": $(wc -c < "$file"), \"size_gz\": $(gzip -c "$file" | wc -c)}}" + done | jq -s 'add' -c) + + echo "files=$FILES" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v4 + + - name: Get dist files size (from pull request) + id: pr-dist-files + run: | + set -e + + FILES=$(find src -mindepth 2 -path '*/assets/dist/*' \( -name "*.js" -o -name "*.css" \) -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do + echo "{\"$file\": {\"size\": $(wc -c < "$file"), \"size_gz\": $(gzip -c "$file" | wc -c)}}" + done | jq -s 'add' -c) + + echo "files=$FILES" >> $GITHUB_OUTPUT + + - name: Generate the diff + id: diff + uses: actions/github-script@v7 + env: + BASE_DIST_FILES: ${{ steps.base-dist-files.outputs.files }} + PR_DIST_FILES: ${{ steps.pr-dist-files.outputs.files }} + with: + result-encoding: string + script: | + const fs = require('fs') + const { main } = await import('${{ github.workspace }}/.github/generate-dist-files-size-diff.mjs') + + const diff = await main() + console.log(diff); + + fs.writeFileSync(process.env.GITHUB_WORKSPACE + '/dist-size.md', diff) + + - name: Upload the diff + uses: actions/upload-artifact@v4 + with: + name: dist-size-${{ github.event.number }} + path: ./dist-size.md From 93d08d06a82da1f41b2876a5b7dd839da8efb867 Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sun, 3 Nov 2024 10:38:26 +0100 Subject: [PATCH 11/42] Minor adjustments after #2269 --- .../dist-files-size-diff-comment.yaml | 20 +++++++++++++++---- .github/workflows/dist-files-size-diff.yaml | 18 ++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dist-files-size-diff-comment.yaml b/.github/workflows/dist-files-size-diff-comment.yaml index d43f79c0a74..40d1e928b20 100644 --- a/.github/workflows/dist-files-size-diff-comment.yaml +++ b/.github/workflows/dist-files-size-diff-comment.yaml @@ -10,13 +10,25 @@ jobs: dist-files-size-diff: runs-on: ubuntu-latest steps: - - name: Download artifact + - name: Download dist-size-diff artifact uses: actions/download-artifact@v4 with: - name: dist-size-${{ github.event.number }} + name: dist-size-diff + run-id: ${{ github.event.workflow_run.id }} + + - name: Download pr-number artifact + uses: actions/download-artifact@v4 + with: + name: pr-number + run-id: ${{ github.event.workflow_run.id }} + + - name: Read pr-number artifact to env var + id: read-pr-number + run: | + echo "::set-output name=pr-number::$(cat ./pr-number)" - name: Comment on the pull request (if success) - if: ${{ always() && steps.diff.conclusion == 'success' }} uses: marocchino/sticky-pull-request-comment@v2 with: - path: ./dist-size.md + number: ${{ steps.read-pr-number.outputs.pr-number }} + path: ./dist-size-diff.md diff --git a/.github/workflows/dist-files-size-diff.yaml b/.github/workflows/dist-files-size-diff.yaml index b690047decc..f6957733f27 100644 --- a/.github/workflows/dist-files-size-diff.yaml +++ b/.github/workflows/dist-files-size-diff.yaml @@ -59,10 +59,22 @@ jobs: const diff = await main() console.log(diff); - fs.writeFileSync(process.env.GITHUB_WORKSPACE + '/dist-size.md', diff) + fs.writeFileSync(process.env.GITHUB_WORKSPACE + '/dist-size-diff.md', diff) - name: Upload the diff uses: actions/upload-artifact@v4 with: - name: dist-size-${{ github.event.number }} - path: ./dist-size.md + name: dist-size-diff + path: ./dist-size-diff.md + + - name: Save PR number + env: + PR_NUMBER: ${{ github.event.number }} + run: | + echo $PR_NUMBER > ./pr-number + + - name: Upload the PR number + uses: actions/upload-artifact@v4 + with: + name: pr-number + path: ./pr-number From f878dc7cb44703c5b9abd1eb707a903aba145001 Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sun, 3 Nov 2024 10:44:08 +0100 Subject: [PATCH 12/42] Test diff size (2) --- .../dist-files-size-diff-comment.yaml | 11 +++------- .github/workflows/dist-files-size-diff.yaml | 20 +++++++------------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/.github/workflows/dist-files-size-diff-comment.yaml b/.github/workflows/dist-files-size-diff-comment.yaml index 40d1e928b20..fb2d53285e4 100644 --- a/.github/workflows/dist-files-size-diff-comment.yaml +++ b/.github/workflows/dist-files-size-diff-comment.yaml @@ -10,17 +10,12 @@ jobs: dist-files-size-diff: runs-on: ubuntu-latest steps: - - name: Download dist-size-diff artifact + - name: Download artifacts uses: actions/download-artifact@v4 with: name: dist-size-diff run-id: ${{ github.event.workflow_run.id }} - - - name: Download pr-number artifact - uses: actions/download-artifact@v4 - with: - name: pr-number - run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - name: Read pr-number artifact to env var id: read-pr-number @@ -31,4 +26,4 @@ jobs: uses: marocchino/sticky-pull-request-comment@v2 with: number: ${{ steps.read-pr-number.outputs.pr-number }} - path: ./dist-size-diff.md + path: ./diff.md diff --git a/.github/workflows/dist-files-size-diff.yaml b/.github/workflows/dist-files-size-diff.yaml index f6957733f27..c95b578f51b 100644 --- a/.github/workflows/dist-files-size-diff.yaml +++ b/.github/workflows/dist-files-size-diff.yaml @@ -60,21 +60,15 @@ jobs: console.log(diff); fs.writeFileSync(process.env.GITHUB_WORKSPACE + '/dist-size-diff.md', diff) - - - name: Upload the diff - uses: actions/upload-artifact@v4 - with: - name: dist-size-diff - path: ./dist-size-diff.md - name: Save PR number - env: - PR_NUMBER: ${{ github.event.number }} run: | - echo $PR_NUMBER > ./pr-number - - - name: Upload the PR number + echo "${{ github.event.number }}" > pr-number + + - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: pr-number - path: ./pr-number + name: dist-size-diff + path: | + ./diff.md + ./pr-number From d667783dd028a90dbf17b08bda330268d18abe9f Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sun, 3 Nov 2024 11:29:54 +0100 Subject: [PATCH 13/42] Test diff size (3) --- .github/workflows/dist-files-size-diff-comment.yaml | 2 +- .github/workflows/dist-files-size-diff.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dist-files-size-diff-comment.yaml b/.github/workflows/dist-files-size-diff-comment.yaml index fb2d53285e4..95134499699 100644 --- a/.github/workflows/dist-files-size-diff-comment.yaml +++ b/.github/workflows/dist-files-size-diff-comment.yaml @@ -20,7 +20,7 @@ jobs: - name: Read pr-number artifact to env var id: read-pr-number run: | - echo "::set-output name=pr-number::$(cat ./pr-number)" + echo "pr-number=$(cat ./pr-number)" >> $GITHUB_OUTPUT - name: Comment on the pull request (if success) uses: marocchino/sticky-pull-request-comment@v2 diff --git a/.github/workflows/dist-files-size-diff.yaml b/.github/workflows/dist-files-size-diff.yaml index c95b578f51b..cf5eabd84a2 100644 --- a/.github/workflows/dist-files-size-diff.yaml +++ b/.github/workflows/dist-files-size-diff.yaml @@ -59,7 +59,7 @@ jobs: const diff = await main() console.log(diff); - fs.writeFileSync(process.env.GITHUB_WORKSPACE + '/dist-size-diff.md', diff) + fs.writeFileSync(process.env.GITHUB_WORKSPACE + '/diff.md', diff) - name: Save PR number run: | From c4d8bd48a1ffb9bd0e34bd18a95ef9e1cb18227d Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sun, 3 Nov 2024 11:36:07 +0100 Subject: [PATCH 14/42] Test diff size (4) --- .github/generate-dist-files-size-diff.mjs | 4 ++-- .github/workflows/dist-files-size-diff.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/generate-dist-files-size-diff.mjs b/.github/generate-dist-files-size-diff.mjs index fc909daf1a1..3f9022d1c4b 100644 --- a/.github/generate-dist-files-size-diff.mjs +++ b/.github/generate-dist-files-size-diff.mjs @@ -72,7 +72,7 @@ export function main() { const base = JSON.parse(process.env.BASE_DIST_FILES); /** @type {Record} */ const pr = JSON.parse(process.env.PR_DIST_FILES); - let output = '

πŸ“Š Dist packagesFiles size difference

\n\n'; + let output = '

πŸ“Š Packages dist files size difference

\n\n'; /** * @type {Map FileBefore (Size / Gzip)After (Size / Gzip) diff --git a/.github/workflows/dist-files-size-diff.yaml b/.github/workflows/dist-files-size-diff.yaml index cf5eabd84a2..ef80d89abc4 100644 --- a/.github/workflows/dist-files-size-diff.yaml +++ b/.github/workflows/dist-files-size-diff.yaml @@ -25,7 +25,7 @@ jobs: run: | set -e - FILES=$(find src -mindepth 2 -path '*/assets/dist/*' \( -name "*.js" -o -name "*.css" \) -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do + FILES=$(find src -mindepth 2 -type f -path '*/assets/dist/*' -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do echo "{\"$file\": {\"size\": $(wc -c < "$file"), \"size_gz\": $(gzip -c "$file" | wc -c)}}" done | jq -s 'add' -c) @@ -38,7 +38,7 @@ jobs: run: | set -e - FILES=$(find src -mindepth 2 -path '*/assets/dist/*' \( -name "*.js" -o -name "*.css" \) -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do + FILES=$(find src -mindepth 2 -type f -path '*/assets/dist/*' -not \( -path '*/tests/*' -o -path '*/public/*' -o -path '*/vendor/*' \) | sort | while read -r file; do echo "{\"$file\": {\"size\": $(wc -c < "$file"), \"size_gz\": $(gzip -c "$file" | wc -c)}}" done | jq -s 'add' -c) From ceccf7942989a5dbd53d78453958aac61cc1e51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sun, 3 Nov 2024 20:06:12 +0100 Subject: [PATCH 15/42] [Site] Fix FileTree markup (minor) --- ux.symfony.com/templates/components/FileTree.html.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ux.symfony.com/templates/components/FileTree.html.twig b/ux.symfony.com/templates/components/FileTree.html.twig index 70519766053..1f8bb94b63e 100644 --- a/ux.symfony.com/templates/components/FileTree.html.twig +++ b/ux.symfony.com/templates/components/FileTree.html.twig @@ -1,6 +1,6 @@ -
+
    {{ _self.fileTree(files) }} -
+ {% macro fileTree(files) %} {% for file_info in files %} From 3b7d1f46b6b4c06a7ca0fcdd402a6fcf68682826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Mon, 4 Nov 2024 01:58:50 +0100 Subject: [PATCH 16/42] [Site] Update demo components paths As mentionned in #2333, demo component classes did not follow current "default" configuration, leading to paths not in line with documentation. Easier than anticipated to fix. --- ux.symfony.com/config/packages/twig_component.yaml | 6 +++--- ux.symfony.com/src/Twig/{ => Components}/Alert.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/BootstrapModal.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/DinoChart.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/DocsLink.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/FoodVote.php | 2 +- .../src/Twig/{ => Components}/HomepageTerminalSwapper.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/InlineEditFood.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/InvoiceCreator.php | 2 +- .../src/Twig/{ => Components}/InvoiceCreatorLineItem.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/MealPlanner.php | 2 +- .../src/Twig/{ => Components}/NewCategoryForm.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/NewProductForm.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/ProductGrid.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/ProductGrid2.php | 2 +- .../src/Twig/{ => Components}/RegistrationForm.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/Terminal.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/TodoListForm.php | 2 +- ux.symfony.com/src/Twig/{ => Components}/UploadFiles.php | 2 +- .../demos/live_component/auto_validating_form.html.twig | 2 +- .../templates/demos/live_component/bootstrap.html.twig | 2 +- .../templates/demos/live_component/chartjs.html.twig | 2 +- .../demos/live_component/dependent_form_fields.html.twig | 2 +- .../demos/live_component/form_collection_type.html.twig | 2 +- .../demos/live_component/infinite_scroll.html.twig | 2 +- .../templates/demos/live_component/inline_edit.html.twig | 2 +- .../templates/demos/live_component/invoice.html.twig | 4 ++-- .../templates/demos/live_component/product_form.html.twig | 6 +++--- .../templates/demos/live_component/upload.html.twig | 2 +- .../templates/demos/live_component/voting.html.twig | 2 +- .../templates/ux_packages/twig_component.html.twig | 2 +- 31 files changed, 36 insertions(+), 36 deletions(-) rename ux.symfony.com/src/Twig/{ => Components}/Alert.php (94%) rename ux.symfony.com/src/Twig/{ => Components}/BootstrapModal.php (92%) rename ux.symfony.com/src/Twig/{ => Components}/DinoChart.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/DocsLink.php (95%) rename ux.symfony.com/src/Twig/{ => Components}/FoodVote.php (97%) rename ux.symfony.com/src/Twig/{ => Components}/HomepageTerminalSwapper.php (97%) rename ux.symfony.com/src/Twig/{ => Components}/InlineEditFood.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/InvoiceCreator.php (99%) rename ux.symfony.com/src/Twig/{ => Components}/InvoiceCreatorLineItem.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/MealPlanner.php (96%) rename ux.symfony.com/src/Twig/{ => Components}/NewCategoryForm.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/NewProductForm.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/ProductGrid.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/ProductGrid2.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/RegistrationForm.php (98%) rename ux.symfony.com/src/Twig/{ => Components}/Terminal.php (95%) rename ux.symfony.com/src/Twig/{ => Components}/TodoListForm.php (96%) rename ux.symfony.com/src/Twig/{ => Components}/UploadFiles.php (98%) diff --git a/ux.symfony.com/config/packages/twig_component.yaml b/ux.symfony.com/config/packages/twig_component.yaml index 9322e1475a8..388d533e4ec 100644 --- a/ux.symfony.com/config/packages/twig_component.yaml +++ b/ux.symfony.com/config/packages/twig_component.yaml @@ -1,10 +1,10 @@ twig_component: defaults: - App\Twig\: 'components/' + App\Twig\Components\: 'components/' + + # Custom namespace for MemoryDemo App\LiveMemory\Component\: template_directory: 'demos/live_memory/components/LiveMemory/' name_prefix: 'LiveMemory:' - - #anonymous_template_directory: 'demos/live_memory/components/' anonymous_template_directory: 'components/' diff --git a/ux.symfony.com/src/Twig/Alert.php b/ux.symfony.com/src/Twig/Components/Alert.php similarity index 94% rename from ux.symfony.com/src/Twig/Alert.php rename to ux.symfony.com/src/Twig/Components/Alert.php index f24dfcd4b00..00f8d8fc0a1 100644 --- a/ux.symfony.com/src/Twig/Alert.php +++ b/ux.symfony.com/src/Twig/Components/Alert.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; diff --git a/ux.symfony.com/src/Twig/BootstrapModal.php b/ux.symfony.com/src/Twig/Components/BootstrapModal.php similarity index 92% rename from ux.symfony.com/src/Twig/BootstrapModal.php rename to ux.symfony.com/src/Twig/Components/BootstrapModal.php index 96cf003c3f3..51063999576 100644 --- a/ux.symfony.com/src/Twig/BootstrapModal.php +++ b/ux.symfony.com/src/Twig/Components/BootstrapModal.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; diff --git a/ux.symfony.com/src/Twig/DinoChart.php b/ux.symfony.com/src/Twig/Components/DinoChart.php similarity index 98% rename from ux.symfony.com/src/Twig/DinoChart.php rename to ux.symfony.com/src/Twig/Components/DinoChart.php index 1c49e80c08b..ed4fc14bff8 100644 --- a/ux.symfony.com/src/Twig/DinoChart.php +++ b/ux.symfony.com/src/Twig/Components/DinoChart.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Service\DinoStatsService; use Symfony\UX\Chartjs\Builder\ChartBuilderInterface; diff --git a/ux.symfony.com/src/Twig/DocsLink.php b/ux.symfony.com/src/Twig/Components/DocsLink.php similarity index 95% rename from ux.symfony.com/src/Twig/DocsLink.php rename to ux.symfony.com/src/Twig/Components/DocsLink.php index 7dd6e75e550..e057fa8745f 100644 --- a/ux.symfony.com/src/Twig/DocsLink.php +++ b/ux.symfony.com/src/Twig/Components/DocsLink.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate; diff --git a/ux.symfony.com/src/Twig/FoodVote.php b/ux.symfony.com/src/Twig/Components/FoodVote.php similarity index 97% rename from ux.symfony.com/src/Twig/FoodVote.php rename to ux.symfony.com/src/Twig/Components/FoodVote.php index 3822ba96c23..40395dafbc8 100644 --- a/ux.symfony.com/src/Twig/FoodVote.php +++ b/ux.symfony.com/src/Twig/Components/FoodVote.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Entity\Food; use App\Repository\FoodRepository; diff --git a/ux.symfony.com/src/Twig/HomepageTerminalSwapper.php b/ux.symfony.com/src/Twig/Components/HomepageTerminalSwapper.php similarity index 97% rename from ux.symfony.com/src/Twig/HomepageTerminalSwapper.php rename to ux.symfony.com/src/Twig/Components/HomepageTerminalSwapper.php index dca67b402af..b126bc5d791 100644 --- a/ux.symfony.com/src/Twig/HomepageTerminalSwapper.php +++ b/ux.symfony.com/src/Twig/Components/HomepageTerminalSwapper.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Model\UxPackage; use App\Service\UxPackageRepository; diff --git a/ux.symfony.com/src/Twig/InlineEditFood.php b/ux.symfony.com/src/Twig/Components/InlineEditFood.php similarity index 98% rename from ux.symfony.com/src/Twig/InlineEditFood.php rename to ux.symfony.com/src/Twig/Components/InlineEditFood.php index 5923ac946a8..2753be3b4f4 100644 --- a/ux.symfony.com/src/Twig/InlineEditFood.php +++ b/ux.symfony.com/src/Twig/Components/InlineEditFood.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Entity\Food; use Doctrine\ORM\EntityManagerInterface; diff --git a/ux.symfony.com/src/Twig/InvoiceCreator.php b/ux.symfony.com/src/Twig/Components/InvoiceCreator.php similarity index 99% rename from ux.symfony.com/src/Twig/InvoiceCreator.php rename to ux.symfony.com/src/Twig/Components/InvoiceCreator.php index eff32b2846e..14c2256143d 100644 --- a/ux.symfony.com/src/Twig/InvoiceCreator.php +++ b/ux.symfony.com/src/Twig/Components/InvoiceCreator.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Entity\Invoice; use App\Entity\InvoiceItem; diff --git a/ux.symfony.com/src/Twig/InvoiceCreatorLineItem.php b/ux.symfony.com/src/Twig/Components/InvoiceCreatorLineItem.php similarity index 98% rename from ux.symfony.com/src/Twig/InvoiceCreatorLineItem.php rename to ux.symfony.com/src/Twig/Components/InvoiceCreatorLineItem.php index 105e6f3ce6f..660ce9de790 100644 --- a/ux.symfony.com/src/Twig/InvoiceCreatorLineItem.php +++ b/ux.symfony.com/src/Twig/Components/InvoiceCreatorLineItem.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Entity\Product; use App\Repository\ProductRepository; diff --git a/ux.symfony.com/src/Twig/MealPlanner.php b/ux.symfony.com/src/Twig/Components/MealPlanner.php similarity index 96% rename from ux.symfony.com/src/Twig/MealPlanner.php rename to ux.symfony.com/src/Twig/Components/MealPlanner.php index 30e5f6c772b..93db6133ecf 100644 --- a/ux.symfony.com/src/Twig/MealPlanner.php +++ b/ux.symfony.com/src/Twig/Components/MealPlanner.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Form\MealPlannerForm; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; diff --git a/ux.symfony.com/src/Twig/NewCategoryForm.php b/ux.symfony.com/src/Twig/Components/NewCategoryForm.php similarity index 98% rename from ux.symfony.com/src/Twig/NewCategoryForm.php rename to ux.symfony.com/src/Twig/Components/NewCategoryForm.php index 8f70d26c814..7636e2b1ecf 100644 --- a/ux.symfony.com/src/Twig/NewCategoryForm.php +++ b/ux.symfony.com/src/Twig/Components/NewCategoryForm.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Entity\Category; use Doctrine\ORM\EntityManagerInterface; diff --git a/ux.symfony.com/src/Twig/NewProductForm.php b/ux.symfony.com/src/Twig/Components/NewProductForm.php similarity index 98% rename from ux.symfony.com/src/Twig/NewProductForm.php rename to ux.symfony.com/src/Twig/Components/NewProductForm.php index 41e66df73db..bb33fa4f4ee 100644 --- a/ux.symfony.com/src/Twig/NewProductForm.php +++ b/ux.symfony.com/src/Twig/Components/NewProductForm.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Entity\Category; use App\Entity\Product; diff --git a/ux.symfony.com/src/Twig/ProductGrid.php b/ux.symfony.com/src/Twig/Components/ProductGrid.php similarity index 98% rename from ux.symfony.com/src/Twig/ProductGrid.php rename to ux.symfony.com/src/Twig/Components/ProductGrid.php index 11793d2b308..fa2a6ebab97 100644 --- a/ux.symfony.com/src/Twig/ProductGrid.php +++ b/ux.symfony.com/src/Twig/Components/ProductGrid.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Service\EmojiCollection; use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; diff --git a/ux.symfony.com/src/Twig/ProductGrid2.php b/ux.symfony.com/src/Twig/Components/ProductGrid2.php similarity index 98% rename from ux.symfony.com/src/Twig/ProductGrid2.php rename to ux.symfony.com/src/Twig/Components/ProductGrid2.php index 1a71ff3641a..a837bcdb78a 100644 --- a/ux.symfony.com/src/Twig/ProductGrid2.php +++ b/ux.symfony.com/src/Twig/Components/ProductGrid2.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Service\EmojiCollection; use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; diff --git a/ux.symfony.com/src/Twig/RegistrationForm.php b/ux.symfony.com/src/Twig/Components/RegistrationForm.php similarity index 98% rename from ux.symfony.com/src/Twig/RegistrationForm.php rename to ux.symfony.com/src/Twig/Components/RegistrationForm.php index 8ce8733c5bb..f7918900187 100644 --- a/ux.symfony.com/src/Twig/RegistrationForm.php +++ b/ux.symfony.com/src/Twig/Components/RegistrationForm.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Form\RegistrationFormType; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; diff --git a/ux.symfony.com/src/Twig/Terminal.php b/ux.symfony.com/src/Twig/Components/Terminal.php similarity index 95% rename from ux.symfony.com/src/Twig/Terminal.php rename to ux.symfony.com/src/Twig/Components/Terminal.php index 7e943b6f575..6399b5712ac 100644 --- a/ux.symfony.com/src/Twig/Terminal.php +++ b/ux.symfony.com/src/Twig/Components/Terminal.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Util\SourceCleaner; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; diff --git a/ux.symfony.com/src/Twig/TodoListForm.php b/ux.symfony.com/src/Twig/Components/TodoListForm.php similarity index 96% rename from ux.symfony.com/src/Twig/TodoListForm.php rename to ux.symfony.com/src/Twig/Components/TodoListForm.php index 165936f63d9..019bbd8f51b 100644 --- a/ux.symfony.com/src/Twig/TodoListForm.php +++ b/ux.symfony.com/src/Twig/Components/TodoListForm.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use App\Entity\TodoList; use App\Form\TodoListFormType; diff --git a/ux.symfony.com/src/Twig/UploadFiles.php b/ux.symfony.com/src/Twig/Components/UploadFiles.php similarity index 98% rename from ux.symfony.com/src/Twig/UploadFiles.php rename to ux.symfony.com/src/Twig/Components/UploadFiles.php index ce59a21f4e7..824ca5b78ad 100644 --- a/ux.symfony.com/src/Twig/UploadFiles.php +++ b/ux.symfony.com/src/Twig/Components/UploadFiles.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace App\Twig; +namespace App\Twig\Components; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; diff --git a/ux.symfony.com/templates/demos/live_component/auto_validating_form.html.twig b/ux.symfony.com/templates/demos/live_component/auto_validating_form.html.twig index 4a1d8d2b4d7..df3f0affaa3 100644 --- a/ux.symfony.com/templates/demos/live_component/auto_validating_form.html.twig +++ b/ux.symfony.com/templates/demos/live_component/auto_validating_form.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} diff --git a/ux.symfony.com/templates/demos/live_component/bootstrap.html.twig b/ux.symfony.com/templates/demos/live_component/bootstrap.html.twig index 4c3f371515d..0175c33416f 100644 --- a/ux.symfony.com/templates/demos/live_component/bootstrap.html.twig +++ b/ux.symfony.com/templates/demos/live_component/bootstrap.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} diff --git a/ux.symfony.com/templates/demos/live_component/chartjs.html.twig b/ux.symfony.com/templates/demos/live_component/chartjs.html.twig index 58a8881e05f..f9b04b0dace 100644 --- a/ux.symfony.com/templates/demos/live_component/chartjs.html.twig +++ b/ux.symfony.com/templates/demos/live_component/chartjs.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} diff --git a/ux.symfony.com/templates/demos/live_component/dependent_form_fields.html.twig b/ux.symfony.com/templates/demos/live_component/dependent_form_fields.html.twig index bbb69b83c2f..4ee03984bb4 100644 --- a/ux.symfony.com/templates/demos/live_component/dependent_form_fields.html.twig +++ b/ux.symfony.com/templates/demos/live_component/dependent_form_fields.html.twig @@ -2,7 +2,7 @@ {% block code_block_full %} diff --git a/ux.symfony.com/templates/demos/live_component/form_collection_type.html.twig b/ux.symfony.com/templates/demos/live_component/form_collection_type.html.twig index 4c3f371515d..0175c33416f 100644 --- a/ux.symfony.com/templates/demos/live_component/form_collection_type.html.twig +++ b/ux.symfony.com/templates/demos/live_component/form_collection_type.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} diff --git a/ux.symfony.com/templates/demos/live_component/infinite_scroll.html.twig b/ux.symfony.com/templates/demos/live_component/infinite_scroll.html.twig index 6bdf0dbabcd..fa9a634e5ea 100644 --- a/ux.symfony.com/templates/demos/live_component/infinite_scroll.html.twig +++ b/ux.symfony.com/templates/demos/live_component/infinite_scroll.html.twig @@ -26,7 +26,7 @@
- + This component is quite standard: the page number as a `LiveProp`, a `LiveAction` to load the next page, and a `getItems` method to retrieve the page results. diff --git a/ux.symfony.com/templates/demos/live_component/inline_edit.html.twig b/ux.symfony.com/templates/demos/live_component/inline_edit.html.twig index 2a7628d20b6..233b68f64fc 100644 --- a/ux.symfony.com/templates/demos/live_component/inline_edit.html.twig +++ b/ux.symfony.com/templates/demos/live_component/inline_edit.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} diff --git a/ux.symfony.com/templates/demos/live_component/invoice.html.twig b/ux.symfony.com/templates/demos/live_component/invoice.html.twig index b4c54257771..9d9340b397d 100644 --- a/ux.symfony.com/templates/demos/live_component/invoice.html.twig +++ b/ux.symfony.com/templates/demos/live_component/invoice.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_full %} - + ## Main Component This main component keeps track of the `Invoice` (which may be new) and @@ -30,7 +30,7 @@ data: `productId`, `quantity`, and `isEditing`. It also passes a `key`, which is needed so LiveComponents can track which row is which. - + ## Child Component The child component for each "line item". This handles validating, saving, diff --git a/ux.symfony.com/templates/demos/live_component/product_form.html.twig b/ux.symfony.com/templates/demos/live_component/product_form.html.twig index bb2a7adad32..6aad5da5a10 100644 --- a/ux.symfony.com/templates/demos/live_component/product_form.html.twig +++ b/ux.symfony.com/templates/demos/live_component/product_form.html.twig @@ -5,7 +5,7 @@ {% endblock %} {% block code_block_full %} - + ## New Product Form Live component with a form, `ValidatableComponentTrait` and a @@ -31,7 +31,7 @@ and `data-bs-target="#new-category-modal"`. ## New Category Form @@ -45,7 +45,7 @@ the new `Category` to the database and then does two important things: diff --git a/ux.symfony.com/templates/demos/live_component/upload.html.twig b/ux.symfony.com/templates/demos/live_component/upload.html.twig index 671f4fbd412..246d47b8a03 100644 --- a/ux.symfony.com/templates/demos/live_component/upload.html.twig +++ b/ux.symfony.com/templates/demos/live_component/upload.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} diff --git a/ux.symfony.com/templates/demos/live_component/voting.html.twig b/ux.symfony.com/templates/demos/live_component/voting.html.twig index 776ba909fe1..34da62e0748 100644 --- a/ux.symfony.com/templates/demos/live_component/voting.html.twig +++ b/ux.symfony.com/templates/demos/live_component/voting.html.twig @@ -1,7 +1,7 @@ {% extends 'demos/live_demo.html.twig' %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} diff --git a/ux.symfony.com/templates/ux_packages/twig_component.html.twig b/ux.symfony.com/templates/ux_packages/twig_component.html.twig index 843a33dde1c..91da8abbc18 100644 --- a/ux.symfony.com/templates/ux_packages/twig_component.html.twig +++ b/ux.symfony.com/templates/ux_packages/twig_component.html.twig @@ -16,7 +16,7 @@ {% endblock %} {% block code_block_left %} - + {% endblock %} {% block code_block_right %} From 9eb85399a9e8c7648bd645440785c78b4e24af20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Fri, 1 Nov 2024 06:43:08 +0100 Subject: [PATCH 17/42] [Map] Update documentation --- src/Map/doc/index.rst | 251 +++++++++++++++++++++++++++--------------- 1 file changed, 165 insertions(+), 86 deletions(-) diff --git a/src/Map/doc/index.rst b/src/Map/doc/index.rst index d950ebfe983..799578b4a31 100644 --- a/src/Map/doc/index.rst +++ b/src/Map/doc/index.rst @@ -37,9 +37,18 @@ Configuration is done in your ``config/packages/ux_map.yaml`` file: The ``UX_MAP_DSN`` environment variable configure which renderer to use. +Map renderers +~~~~~~~~~~~~~ + +The Symfony UX Map bundle supports multiple renderers. A map renderer is a +service that provides the code and graphic assets required to render and +interact with a map in the browser. + Available renderers ~~~~~~~~~~~~~~~~~~~ +UX Map ships with two renderers: `Google Maps`_ and `Leaflet`_. + ============== =============================================================== Renderer ============== =============================================================== @@ -49,104 +58,173 @@ Renderer **DSN**: ``UX_MAP_DSN=leaflet://default`` \ ============== =============================================================== -Usage ------ +.. tip:: + + Read the `Symfony UX Map Leaflet bridge docs`_ and the + `Symfony UX Map Google Maps brige docs`_ to learn about the configuration + options available for each renderer. -Creating and rendering -~~~~~~~~~~~~~~~~~~~~~~ +Create a map +------------ -A map is created by calling ``new Map()``. You can configure the center, zoom, and add markers:: - - namespace App\Controller; +A map is created by calling ``new Map()``. You can configure the center, zoom, and add markers. +Start by creating a new map instance:: - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Routing\Attribute\Route; - use Symfony\UX\Map\InfoWindow; use Symfony\UX\Map\Map; - use Symfony\UX\Map\Marker; + + // Create a new map instance + $myMap = (new Map()); + +Center and zoom +~~~~~~~~~~~~~~~ + +You can set the center and zoom of the map using the ``center()`` and ``zoom()`` methods: + + use Symfony\UX\Map\Map; use Symfony\UX\Map\Point; - final class HomeController extends AbstractController - { - #[Route('/')] - public function __invoke(): Response - { - // 1. Create a new map instance - $myMap = (new Map()) - // Explicitly set the center and zoom - ->center(new Point(46.903354, 1.888334)) - ->zoom(6) - // Or automatically fit the bounds to the markers - ->fitBoundsToMarkers() - ; + $myMap - // 2. You can add markers - $myMap - ->addMarker(new Marker( - position: new Point(48.8566, 2.3522), - title: 'Paris' - )) - - // With an info window associated to the marker: - ->addMarker(new Marker( - position: new Point(45.7640, 4.8357), - title: 'Lyon', - infoWindow: new InfoWindow( - headerContent: 'Lyon', - content: 'The French town in the historic RhΓ΄ne-Alpes region, located at the junction of the RhΓ΄ne and SaΓ΄ne rivers.' - ) - )) - - // You can also pass arbitrary data via the `extra` option in both the marker - // and the infoWindow; you can later use this data in your custom Stimulus controllers - ->addMarker(new Marker( - // ... - extra: [ - 'icon_mask_url' => 'https://maps.gstatic.com/mapfiles/place_api/icons/v2/tree_pinlet.svg', - ], - infoWindow: new InfoWindow( - // ... - extra: [ - 'num_items' => 3, - 'includes_link' => true, - ], - ), - ) - ; - - // 3. You can also add Polygons, which represents an area enclosed by a series of `Point` instances - $myMap->addPolygon(new Polygon( - points: [ - new Point(48.8566, 2.3522), - new Point(45.7640, 4.8357), - new Point(43.2965, 5.3698), - new Point(44.8378, -0.5792), + // Explicitly set the center and zoom + ->center(new Point(46.903354, 1.888334)) + ->zoom(6) + + // Or automatically fit the bounds to the markers + ->fitBoundsToMarkers() + ; + +Add markers +~~~~~~~~~~~ + +You can add markers to a map using the ``addMarker()`` method: + + $myMap + ->addMarker(new Marker( + position: new Point(48.8566, 2.3522), + title: 'Paris' + )) + + // With an info window associated to the marker: + ->addMarker(new Marker( + position: new Point(45.7640, 4.8357), + title: 'Lyon', + infoWindow: new InfoWindow( + headerContent: 'Lyon', + content: 'The French town in the historic RhΓ΄ne-Alpes region, located at the junction of the RhΓ΄ne and SaΓ΄ne rivers.' + ) + )) + + // You can also pass arbitrary data via the `extra` option in both the marker + // and the infoWindow; you can later use this data in your custom Stimulus controllers + ->addMarker(new Marker( + // ... + extra: [ + 'icon_mask_url' => 'https://maps.gstatic.com/mapfiles/place_api/icons/v2/tree_pinlet.svg', + ], + infoWindow: new InfoWindow( + // ... + extra: [ + 'num_items' => 3, + 'includes_link' => true, ], - infoWindow: new InfoWindow( - content: 'Paris, Lyon, Marseille, Bordeaux', - ), - )); - - // 4. And inject the map in your template to render it - return $this->render('contact/index.html.twig', [ - 'my_map' => $myMap, - ]); - } - } + ), + ) + ; + +Add Polygons +~~~~~~~~~~~~ + +You can also add Polygons, which represents an area enclosed by a series of ``Point`` instances: + + $myMap->addPolygon(new Polygon( + points: [ + new Point(48.8566, 2.3522), + new Point(45.7640, 4.8357), + new Point(43.2965, 5.3698), + new Point(44.8378, -0.5792), + ], + infoWindow: new InfoWindow( + content: 'Paris, Lyon, Marseille, Bordeaux', + ), + )); + +Render a map +------------ To render a map in your Twig template, use the ``ux_map`` Twig function, e.g.: +To be visible, the map must have a defined height: + .. code-block:: twig - {# to be visible, the map must have a defined height #} {{ ux_map(my_map, { style: 'height: 300px' }) }} - {# you can add custom HTML attributes too #} +You can add custom HTML attributes too: + +.. code-block:: twig + {{ ux_map(my_map, { style: 'height: 300px', id: 'events-map', class: 'mb-3' }) }} -Extend the default behavior -~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Twig Function ``ux_map()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``ux_map()`` Twig function allows you to create and render a map in your Twig +templates. The function accepts the same arguments as the ``Map`` class: + +.. code-block:: html+twig + + {{ ux_map( + center: [51.5074, 0.1278], + zoom: 3, + markers: [ + { position: [51.5074, 0.1278], title: 'London' }, + { position: [48.8566, 2.3522], title: 'Paris' }, + { + position: [40.7128, -74.0060], + title: 'New York', + infoWindow: { content: 'Welcome to New York' } + }, + ], + attributes: { + class: 'foo', + style: 'height: 800px; width: 100%; border: 4px solid red; margin-block: 10vh;', + } + ) }} + +Twig Component ```` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Alternatively, you can use the ```` component. + +.. code-block:: html+twig + + + +The ```` component requires the `Twig Component`_ package. + +.. code-block:: terminal + + $ composer require symfony/ux-twig-component + +Interact with the map +~~~~~~~~~~~~~~~~~~~~~ Symfony UX Map allows you to extend its default behavior using a custom Stimulus controller: @@ -219,11 +297,6 @@ Symfony UX Map allows you to extend its default behavior using a custom Stimulus } } -.. tip:: - - Read the `Symfony UX Map Leaflet bridge docs`_ and the - `Symfony UX Map Google Maps brige docs`_ to learn about the exact code - needed to customize the markers. Then, you can use this controller in your template: @@ -231,6 +304,12 @@ Then, you can use this controller in your template: {{ ux_map(my_map, { 'data-controller': 'mymap', style: 'height: 300px' }) }} +.. tip:: + + Read the `Symfony UX Map Leaflet bridge docs`_ and the + `Symfony UX Map Google Maps brige docs`_ to learn about the exact code + needed to customize the markers. + Backward Compatibility promise ------------------------------ From 9ec2a7187a2aeb0abe8353361d5064cb4fe51b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Fri, 1 Nov 2024 01:01:11 +0100 Subject: [PATCH 18/42] [TwigComponent] Optimize TwigPreLexer --- src/TwigComponent/src/Twig/TwigPreLexer.php | 105 ++++++-------------- 1 file changed, 32 insertions(+), 73 deletions(-) diff --git a/src/TwigComponent/src/Twig/TwigPreLexer.php b/src/TwigComponent/src/Twig/TwigPreLexer.php index 2e0fdbe7199..5d6d41f3fa3 100644 --- a/src/TwigComponent/src/Twig/TwigPreLexer.php +++ b/src/TwigComponent/src/Twig/TwigPreLexer.php @@ -39,7 +39,7 @@ public function preLexComponents(string $input): string return $input; } - $this->input = $input; + $this->input = $input = str_replace(["\r\n", "\r"], "\n", $input); $this->length = \strlen($input); $output = ''; @@ -126,7 +126,8 @@ public function preLexComponents(string $input): string // open the default block if (!empty($this->currentComponents) && !$this->currentComponents[\count($this->currentComponents) - 1]['hasDefaultBlock']) { - $output .= $this->addDefaultBlock(); + $output .= '{% block content %}'; + $this->currentComponents[\count($this->currentComponents) - 1]['hasDefaultBlock'] = true; } $attributes = $this->consumeAttributes($componentName); @@ -182,7 +183,8 @@ public function preLexComponents(string $input): string && preg_match('/\S/', $char) && !$this->check('{% block') ) { - $output .= $this->addDefaultBlock(); + $this->currentComponents[\count($this->currentComponents) - 1]['hasDefaultBlock'] = true; + $output .= '{% block content %}'; } $output .= $char; @@ -199,29 +201,14 @@ public function preLexComponents(string $input): string private function consumeComponentName(?string $customExceptionMessage = null): string { - $start = $this->position; - while ($this->position < $this->length && preg_match('/[A-Za-z0-9_:@\-.]/', $this->input[$this->position])) { - ++$this->position; - } + if (preg_match('/\G[A-Za-z0-9_:@\-.]+/', $this->input, $matches, 0, $this->position)) { + $componentName = $matches[0]; + $this->position += \strlen($componentName); - $componentName = substr($this->input, $start, $this->position - $start); - - if (empty($componentName)) { - $exceptionMessage = $customExceptionMessage; - if (null == $exceptionMessage) { - $exceptionMessage = 'Expected component name when resolving the "line); + return $componentName; } - return $componentName; - } - - private function consumeAttributeName(string $componentName): string - { - $message = \sprintf('Expected attribute name when parsing the "consumeComponentName($message); + throw new SyntaxError($customExceptionMessage ?? 'Expected component name when resolving the "line); } private function consumeAttributes(string $componentName): string @@ -251,7 +238,9 @@ private function consumeAttributes(string $componentName): string $isAttributeDynamic = true; } - $key = $this->consumeAttributeName($componentName); + $message = \sprintf('Expected attribute name when parsing the "consumeComponentName($message); // -> someProp: true if (!$this->check('=')) { @@ -290,9 +279,8 @@ private function consumeAttributes(string $componentName): string */ private function consume(string $string): bool { - $stringLength = \strlen($string); - if (substr($this->input, $this->position, $stringLength) === $string) { - $this->position += $stringLength; + if (str_starts_with(substr($this->input, $this->position), $string)) { + $this->position += \strlen($string); return true; } @@ -325,31 +313,25 @@ private function consumeChar($validChars = null): string */ private function consumeUntil(string $endString): string { - $start = $this->position; - $endCharLength = \strlen($endString); + if (false === $endPosition = strpos($this->input, $endString, $this->position)) { + $start = $this->position; + $this->position = $this->length; - while ($this->position < $this->length) { - if (substr($this->input, $this->position, $endCharLength) === $endString) { - break; - } - - if ("\n" === $this->input[$this->position]) { - ++$this->line; - } - ++$this->position; + return substr($this->input, $start); } - return substr($this->input, $start, $this->position - $start); + $content = substr($this->input, $this->position, $endPosition - $this->position); + $this->line += substr_count($content, "\n"); + $this->position = $endPosition; + + return $content; } private function consumeWhitespace(): void { - while ($this->position < $this->length && preg_match('/\s/', $this->input[$this->position])) { - if ("\n" === $this->input[$this->position]) { - ++$this->line; - } - ++$this->position; - } + $whitespace = substr($this->input, $this->position, strspn($this->input, " \t\n\r\0\x0B", $this->position)); + $this->line += substr_count($whitespace, "\n"); + $this->position += \strlen($whitespace); } /** @@ -374,18 +356,8 @@ private function expectAndConsumeChar(string $char): void private function check(string $chars): bool { - $charsLength = \strlen($chars); - if ($this->position + $charsLength > $this->length) { - return false; - } - - for ($i = 0; $i < $charsLength; ++$i) { - if ($this->input[$this->position + $i] !== $chars[$i]) { - return false; - } - } - - return true; + return $this->position + \strlen($chars) <= $this->length + && 0 === substr_compare($this->input, $chars, $this->position, \strlen($chars)); } private function consumeBlock(string $componentName): string @@ -409,7 +381,7 @@ private function consumeBlock(string $componentName): string $output = "{% block {$blockName} %}"; $closingTag = ''; - if (!$this->doesStringEventuallyExist($closingTag)) { + if (false === strpos($this->input, $closingTag, $this->position)) { throw new SyntaxError("Expected closing tag '{$closingTag}' for block '{$blockName}'.", $this->line); } $blockContents = $this->consumeUntilEndBlock(); @@ -448,7 +420,8 @@ private function consumeUntilEndBlock(): string if (!$inComment && '{% endblock %}' === substr($this->input, $this->position, 14)) { if (1 === $depth) { // in this case, we want to advance ALL the way beyond the endblock - $this->position += 14 /* strlen('{% endblock %}') */; + // strlen('{% endblock %}') = 14 + $this->position += 14; break; } else { --$depth; @@ -512,18 +485,4 @@ private function consumeAttributeValue(string $quote): string return implode('~', $parts); } - - private function doesStringEventuallyExist(string $needle): bool - { - $remainingString = substr($this->input, $this->position); - - return str_contains($remainingString, $needle); - } - - private function addDefaultBlock(): string - { - $this->currentComponents[\count($this->currentComponents) - 1]['hasDefaultBlock'] = true; - - return '{% block content %}'; - } } From 64498a676a0ef5ff2ecfec090e84d7e2ab6f280d Mon Sep 17 00:00:00 2001 From: LesRouxDominerontLeMonde <105645582+LesRouxDominerontLeMonde@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:32:35 +0100 Subject: [PATCH 19/42] Update index.rst added :: instead of : , visual effect --- src/Map/doc/index.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Map/doc/index.rst b/src/Map/doc/index.rst index 799578b4a31..c6d49cfdc7d 100644 --- a/src/Map/doc/index.rst +++ b/src/Map/doc/index.rst @@ -78,13 +78,12 @@ Start by creating a new map instance:: Center and zoom ~~~~~~~~~~~~~~~ -You can set the center and zoom of the map using the ``center()`` and ``zoom()`` methods: +You can set the center and zoom of the map using the ``center()`` and ``zoom()`` methods:: use Symfony\UX\Map\Map; use Symfony\UX\Map\Point; $myMap - // Explicitly set the center and zoom ->center(new Point(46.903354, 1.888334)) ->zoom(6) @@ -96,7 +95,7 @@ You can set the center and zoom of the map using the ``center()`` and ``zoom()`` Add markers ~~~~~~~~~~~ -You can add markers to a map using the ``addMarker()`` method: +You can add markers to a map using the ``addMarker()`` method:: $myMap ->addMarker(new Marker( @@ -134,7 +133,7 @@ You can add markers to a map using the ``addMarker()`` method: Add Polygons ~~~~~~~~~~~~ -You can also add Polygons, which represents an area enclosed by a series of ``Point`` instances: +You can also add Polygons, which represents an area enclosed by a series of ``Point`` instances:: $myMap->addPolygon(new Polygon( points: [ From d906c6e62882862755079b6de5f5b0cb596ec808 Mon Sep 17 00:00:00 2001 From: Cyril Lussiana Date: Mon, 4 Nov 2024 20:33:05 +0100 Subject: [PATCH 20/42] fix: replace / by DIRECTORY_SEPARATOR --- src/TwigComponent/src/Command/TwigComponentDebugCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php index 4b43216acdf..68be2f29f2a 100644 --- a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php +++ b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php @@ -182,12 +182,12 @@ private function findAnonymousComponents(): array ->name('*.html.twig') ; foreach ($finderTemplates as $template) { - $component = str_replace('/', ':', $template->getRelativePathname()); + $component = str_replace(\DIRECTORY_SEPARATOR, ':', $template->getRelativePathname()); $component = substr($component, 0, -10); // remove file extension ".html.twig" $path = $template->getPath(); if ($template->getRelativePath()) { - $path = \rtrim(\substr($template->getPath(), 0, -1 * \strlen($template->getRelativePath())), '/'); + $path = \rtrim(\substr($template->getPath(), 0, -1 * \strlen($template->getRelativePath())), \DIRECTORY_SEPARATOR); } if (isset($dirs[$path]) && FilesystemLoader::MAIN_NAMESPACE !== $dirs[$path]) { From 18bc31bd29144e5991cd0ea24a59e5dee175cf08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Wed, 6 Nov 2024 03:07:33 +0100 Subject: [PATCH 21/42] [TwigComponent] Improve BlockStack performances BlockStack Quick Optimization Minor change with major impact --- src/TwigComponent/src/BlockStack.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/TwigComponent/src/BlockStack.php b/src/TwigComponent/src/BlockStack.php index f6a249e3d35..1d4cb90ba7a 100644 --- a/src/TwigComponent/src/BlockStack.php +++ b/src/TwigComponent/src/BlockStack.php @@ -28,9 +28,15 @@ final class BlockStack */ private array $stack; + /** + * @var array + */ + private static array $templateIndexStack = []; + public function convert(array $blocks, int $targetEmbeddedTemplateIndex): array { $newBlocks = []; + $hostEmbeddedTemplateIndex = null; foreach ($blocks as $blockName => $block) { // Keep already converted outer blocks untouched if (str_starts_with($blockName, self::OUTER_BLOCK_PREFIX)) { @@ -41,7 +47,7 @@ public function convert(array $blocks, int $targetEmbeddedTemplateIndex): array // Determine the location of the block where it is defined in the host Template. // Each component has its own embedded template. That template's index uniquely // identifies the block definition. - $hostEmbeddedTemplateIndex = $this->findHostEmbeddedTemplateIndex(); + $hostEmbeddedTemplateIndex ??= $this->findHostEmbeddedTemplateIndex(); // Change the name of outer blocks to something unique so blocks of nested components aren't overridden, // which otherwise might cause a recursion loop when nesting components. @@ -69,12 +75,10 @@ private function findHostEmbeddedTemplateIndex(): int { $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT); - $componentTemplateClassName = null; - foreach ($backtrace as $trace) { if (isset($trace['object']) && $trace['object'] instanceof Template) { $classname = $trace['object']::class; - $templateIndex = $this->getTemplateIndexFromTemplateClassname($classname); + $templateIndex = self::getTemplateIndexFromTemplateClassname($classname); if ($templateIndex) { // If there's no template index, then we're in a component template // and we need to go up until we find the embedded template @@ -93,7 +97,7 @@ private function findCallingEmbeddedTemplateIndex(): int foreach ($backtrace as $trace) { if (isset($trace['object']) && $trace['object'] instanceof Template) { - return $this->getTemplateIndexFromTemplateClassname($trace['object']::class); + return self::getTemplateIndexFromTemplateClassname($trace['object']::class); } } } @@ -108,7 +112,7 @@ private function findHostEmbeddedTemplateIndexFromCaller(): int foreach ($backtrace as $trace) { if (isset($trace['object']) && $trace['object'] instanceof Template) { $classname = $trace['object']::class; - $templateIndex = $this->getTemplateIndexFromTemplateClassname($classname); + $templateIndex = self::getTemplateIndexFromTemplateClassname($classname); if (null === $renderer) { if ($templateIndex) { // This class is an embedded template. @@ -139,8 +143,8 @@ private function findHostEmbeddedTemplateIndexFromCaller(): int return 0; } - private function getTemplateIndexFromTemplateClassname(string $classname): int + private static function getTemplateIndexFromTemplateClassname(string $classname): int { - return (int) substr($classname, strrpos($classname, '___') + 3); + return self::$templateIndexStack[$classname] ??= (int) substr($classname, strrpos($classname, '___') + 3); } } From ced7008d6982f7d791537de7c8ea055ef7087ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Wed, 6 Nov 2024 12:17:39 +0100 Subject: [PATCH 22/42] [Site] Update symfony --- ux.symfony.com/composer.lock | 456 +++++++++++++++++------------------ 1 file changed, 228 insertions(+), 228 deletions(-) diff --git a/ux.symfony.com/composer.lock b/ux.symfony.com/composer.lock index 64824239bd2..079768f8127 100644 --- a/ux.symfony.com/composer.lock +++ b/ux.symfony.com/composer.lock @@ -1741,16 +1741,16 @@ }, { "name": "lcobucci/jwt", - "version": "5.4.0", + "version": "5.4.1", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "aac4fd512681fd5cb4b77d2105ab7ec700c72051" + "reference": "848815d2287abd5d3c285482f8e1f501b289a2e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/aac4fd512681fd5cb4b77d2105ab7ec700c72051", - "reference": "aac4fd512681fd5cb4b77d2105ab7ec700c72051", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/848815d2287abd5d3c285482f8e1f501b289a2e7", + "reference": "848815d2287abd5d3c285482f8e1f501b289a2e7", "shasum": "" }, "require": { @@ -1798,7 +1798,7 @@ ], "support": { "issues": "https://github.com/lcobucci/jwt/issues", - "source": "https://github.com/lcobucci/jwt/tree/5.4.0" + "source": "https://github.com/lcobucci/jwt/tree/5.4.1" }, "funding": [ { @@ -1810,7 +1810,7 @@ "type": "patreon" } ], - "time": "2024-10-08T22:06:45+00:00" + "time": "2024-11-06T06:16:04+00:00" }, { "name": "league/commonmark", @@ -2857,16 +2857,16 @@ }, { "name": "symfony/cache", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "1354995a9e758e7141a90ed99248a0e21bee701d" + "reference": "b9ef68c9130fcd3e2db0763e0d6fa866393f2df6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/1354995a9e758e7141a90ed99248a0e21bee701d", - "reference": "1354995a9e758e7141a90ed99248a0e21bee701d", + "url": "https://api.github.com/repos/symfony/cache/zipball/b9ef68c9130fcd3e2db0763e0d6fa866393f2df6", + "reference": "b9ef68c9130fcd3e2db0763e0d6fa866393f2df6", "shasum": "" }, "require": { @@ -2935,7 +2935,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/cache/tree/v7.2.0-BETA2" }, "funding": [ { @@ -2951,7 +2951,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:40:01+00:00" + "time": "2024-11-05T15:35:02+00:00" }, { "name": "symfony/cache-contracts", @@ -3031,16 +3031,16 @@ }, { "name": "symfony/config", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "75cfe49f73d6d43110690e55fb212d697ee598d9" + "reference": "bcd3c4adf0144dee5011bb35454728c38adec055" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/75cfe49f73d6d43110690e55fb212d697ee598d9", - "reference": "75cfe49f73d6d43110690e55fb212d697ee598d9", + "url": "https://api.github.com/repos/symfony/config/zipball/bcd3c4adf0144dee5011bb35454728c38adec055", + "reference": "bcd3c4adf0144dee5011bb35454728c38adec055", "shasum": "" }, "require": { @@ -3086,7 +3086,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/v7.2.0-BETA1" + "source": "https://github.com/symfony/config/tree/v7.2.0-BETA2" }, "funding": [ { @@ -3102,20 +3102,20 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2024-11-04T11:36:24+00:00" }, { "name": "symfony/console", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "de74db6d7c9f4ecabf7b4a1a20655e021b034001" + "reference": "3fda7e592a83a6f487cdce3146f6b3408e6f01de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/de74db6d7c9f4ecabf7b4a1a20655e021b034001", - "reference": "de74db6d7c9f4ecabf7b4a1a20655e021b034001", + "url": "https://api.github.com/repos/symfony/console/zipball/3fda7e592a83a6f487cdce3146f6b3408e6f01de", + "reference": "3fda7e592a83a6f487cdce3146f6b3408e6f01de", "shasum": "" }, "require": { @@ -3179,7 +3179,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/console/tree/v7.2.0-BETA2" }, "funding": [ { @@ -3195,20 +3195,20 @@ "type": "tidelift" } ], - "time": "2024-10-23T06:56:12+00:00" + "time": "2024-11-05T15:35:02+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "6d5c6520d1984bc67af228dd6519e03e58661d7f" + "reference": "f5241adc1796c78f223e96fc3997ca0f4a836635" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/6d5c6520d1984bc67af228dd6519e03e58661d7f", - "reference": "6d5c6520d1984bc67af228dd6519e03e58661d7f", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f5241adc1796c78f223e96fc3997ca0f4a836635", + "reference": "f5241adc1796c78f223e96fc3997ca0f4a836635", "shasum": "" }, "require": { @@ -3259,7 +3259,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/v7.2.0-BETA1" + "source": "https://github.com/symfony/dependency-injection/tree/v7.2.0-BETA2" }, "funding": [ { @@ -3275,7 +3275,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2024-11-06T08:41:34+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3529,16 +3529,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "ad57ca04868ca877e7919c56d20bdfa8024b54d6" + "reference": "672b3dd1ef8b87119b446d67c58c106c43f965fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/ad57ca04868ca877e7919c56d20bdfa8024b54d6", - "reference": "ad57ca04868ca877e7919c56d20bdfa8024b54d6", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/672b3dd1ef8b87119b446d67c58c106c43f965fe", + "reference": "672b3dd1ef8b87119b446d67c58c106c43f965fe", "shasum": "" }, "require": { @@ -3584,7 +3584,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/v7.2.0-BETA1" + "source": "https://github.com/symfony/error-handler/tree/v7.2.0-BETA2" }, "funding": [ { @@ -3600,7 +3600,7 @@ "type": "tidelift" } ], - "time": "2024-10-14T08:54:27+00:00" + "time": "2024-11-05T15:35:02+00:00" }, { "name": "symfony/event-dispatcher", @@ -4119,16 +4119,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "8a7df876a98d15c8b9f01b10397a76d5de548324" + "reference": "7a46f7de39c92cdc29fd86beeb6f16ad1a3e5dd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/8a7df876a98d15c8b9f01b10397a76d5de548324", - "reference": "8a7df876a98d15c8b9f01b10397a76d5de548324", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/7a46f7de39c92cdc29fd86beeb6f16ad1a3e5dd8", + "reference": "7a46f7de39c92cdc29fd86beeb6f16ad1a3e5dd8", "shasum": "" }, "require": { @@ -4249,7 +4249,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/v7.2.0-BETA1" + "source": "https://github.com/symfony/framework-bundle/tree/v7.2.0-BETA2" }, "funding": [ { @@ -4265,20 +4265,20 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2024-11-05T09:05:33+00:00" }, { "name": "symfony/http-client", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "dee07290e432b1dde37dbb4ea1d67663f3cce0bc" + "reference": "730f1bb15938598419e92432e2156fc960dcf782" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/dee07290e432b1dde37dbb4ea1d67663f3cce0bc", - "reference": "dee07290e432b1dde37dbb4ea1d67663f3cce0bc", + "url": "https://api.github.com/repos/symfony/http-client/zipball/730f1bb15938598419e92432e2156fc960dcf782", + "reference": "730f1bb15938598419e92432e2156fc960dcf782", "shasum": "" }, "require": { @@ -4344,7 +4344,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/http-client/tree/v7.2.0-BETA2" }, "funding": [ { @@ -4360,7 +4360,7 @@ "type": "tidelift" } ], - "time": "2024-10-22T19:26:41+00:00" + "time": "2024-11-06T08:44:59+00:00" }, { "name": "symfony/http-client-contracts", @@ -4442,16 +4442,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "735b8519a8bcbf603d3af0430fb1be5c8822af13" + "reference": "9a51d2afa16b17923ecbf0dfd51a71a56a3136d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/735b8519a8bcbf603d3af0430fb1be5c8822af13", - "reference": "735b8519a8bcbf603d3af0430fb1be5c8822af13", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9a51d2afa16b17923ecbf0dfd51a71a56a3136d4", + "reference": "9a51d2afa16b17923ecbf0dfd51a71a56a3136d4", "shasum": "" }, "require": { @@ -4500,7 +4500,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/http-foundation/tree/v7.2.0-BETA2" }, "funding": [ { @@ -4516,20 +4516,20 @@ "type": "tidelift" } ], - "time": "2024-10-23T06:56:12+00:00" + "time": "2024-11-06T09:03:19+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "1d5619199df507f9f03584ae9141924cc148050e" + "reference": "70a5fd8f9614f8ed1f0a1640f00d59047e7619bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1d5619199df507f9f03584ae9141924cc148050e", - "reference": "1d5619199df507f9f03584ae9141924cc148050e", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/70a5fd8f9614f8ed1f0a1640f00d59047e7619bb", + "reference": "70a5fd8f9614f8ed1f0a1640f00d59047e7619bb", "shasum": "" }, "require": { @@ -4614,7 +4614,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/v7.2.0-BETA1" + "source": "https://github.com/symfony/http-kernel/tree/v7.2.0-BETA2" }, "funding": [ { @@ -4630,20 +4630,20 @@ "type": "tidelift" } ], - "time": "2024-10-27T15:21:58+00:00" + "time": "2024-11-06T10:00:45+00:00" }, { "name": "symfony/intl", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "e0c8d9c19b3a52f2d379319fd16298568ce9573d" + "reference": "8069d355b4742a1dc98c92412215d4853fe28c29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/e0c8d9c19b3a52f2d379319fd16298568ce9573d", - "reference": "e0c8d9c19b3a52f2d379319fd16298568ce9573d", + "url": "https://api.github.com/repos/symfony/intl/zipball/8069d355b4742a1dc98c92412215d4853fe28c29", + "reference": "8069d355b4742a1dc98c92412215d4853fe28c29", "shasum": "" }, "require": { @@ -4700,7 +4700,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/intl/tree/v7.2.0-BETA2" }, "funding": [ { @@ -4716,7 +4716,7 @@ "type": "tidelift" } ], - "time": "2024-10-08T07:22:49+00:00" + "time": "2024-11-05T15:35:02+00:00" }, { "name": "symfony/mercure", @@ -4955,16 +4955,16 @@ }, { "name": "symfony/mime", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "e57faea55d255c31b0899f0130c7d9da65fa2ec7" + "reference": "c73ca0f7f11fb609356b84d0d808053bf433880a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/e57faea55d255c31b0899f0130c7d9da65fa2ec7", - "reference": "e57faea55d255c31b0899f0130c7d9da65fa2ec7", + "url": "https://api.github.com/repos/symfony/mime/zipball/c73ca0f7f11fb609356b84d0d808053bf433880a", + "reference": "c73ca0f7f11fb609356b84d0d808053bf433880a", "shasum": "" }, "require": { @@ -5019,7 +5019,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/mime/tree/v7.2.0-BETA2" }, "funding": [ { @@ -5035,7 +5035,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2024-11-05T09:31:08+00:00" }, { "name": "symfony/monolog-bridge", @@ -5828,16 +5828,16 @@ }, { "name": "symfony/process", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "2ad775b9f17c8c9c1fe457750ce191e0f7c1fbff" + "reference": "37f5c1fc0f83db4900ea961c5fc0180e2a279b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/2ad775b9f17c8c9c1fe457750ce191e0f7c1fbff", - "reference": "2ad775b9f17c8c9c1fe457750ce191e0f7c1fbff", + "url": "https://api.github.com/repos/symfony/process/zipball/37f5c1fc0f83db4900ea961c5fc0180e2a279b6a", + "reference": "37f5c1fc0f83db4900ea961c5fc0180e2a279b6a", "shasum": "" }, "require": { @@ -5869,7 +5869,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/process/tree/v7.2.0-BETA2" }, "funding": [ { @@ -5885,7 +5885,7 @@ "type": "tidelift" } ], - "time": "2024-09-26T08:57:56+00:00" + "time": "2024-11-06T09:25:18+00:00" }, { "name": "symfony/property-access", @@ -6049,16 +6049,16 @@ }, { "name": "symfony/routing", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "b9f47730638e96d6ff26f84bd4a7e89073d15634" + "reference": "0782e32f411cf1c4a1ab3f5c074a9b61f3df8e5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/b9f47730638e96d6ff26f84bd4a7e89073d15634", - "reference": "b9f47730638e96d6ff26f84bd4a7e89073d15634", + "url": "https://api.github.com/repos/symfony/routing/zipball/0782e32f411cf1c4a1ab3f5c074a9b61f3df8e5a", + "reference": "0782e32f411cf1c4a1ab3f5c074a9b61f3df8e5a", "shasum": "" }, "require": { @@ -6110,7 +6110,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/routing/tree/v7.2.0-BETA2" }, "funding": [ { @@ -6126,20 +6126,20 @@ "type": "tidelift" } ], - "time": "2024-10-03T12:20:01+00:00" + "time": "2024-11-06T08:41:34+00:00" }, { "name": "symfony/runtime", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "049a9f3bebe7d4d9572e3d4a86f0fb7fe24fb077" + "reference": "46fd79dded7f7a6358dbf9e055ae545fc4bbb8ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/049a9f3bebe7d4d9572e3d4a86f0fb7fe24fb077", - "reference": "049a9f3bebe7d4d9572e3d4a86f0fb7fe24fb077", + "url": "https://api.github.com/repos/symfony/runtime/zipball/46fd79dded7f7a6358dbf9e055ae545fc4bbb8ff", + "reference": "46fd79dded7f7a6358dbf9e055ae545fc4bbb8ff", "shasum": "" }, "require": { @@ -6189,7 +6189,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/runtime/tree/v7.2.0-BETA2" }, "funding": [ { @@ -6205,20 +6205,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2024-11-05T16:46:43+00:00" }, { "name": "symfony/serializer", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "56bcd41f8e8792b15ca363b730e26c7c536a7873" + "reference": "96421e664c2c3077a1e0858a02e62a7a4d66ce79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/56bcd41f8e8792b15ca363b730e26c7c536a7873", - "reference": "56bcd41f8e8792b15ca363b730e26c7c536a7873", + "url": "https://api.github.com/repos/symfony/serializer/zipball/96421e664c2c3077a1e0858a02e62a7a4d66ce79", + "reference": "96421e664c2c3077a1e0858a02e62a7a4d66ce79", "shasum": "" }, "require": { @@ -6288,7 +6288,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/serializer/tree/v7.2.0-BETA2" }, "funding": [ { @@ -6304,7 +6304,7 @@ "type": "tidelift" } ], - "time": "2024-10-22T19:37:21+00:00" + "time": "2024-10-25T18:10:29+00:00" }, { "name": "symfony/service-contracts", @@ -6395,12 +6395,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/stimulus-bundle.git", - "reference": "2dc5431fd4fd84662615b435af7a0a6affd94f2d" + "reference": "d9b83e7132451dfddfa8ef398b50cfa88e490c21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/2dc5431fd4fd84662615b435af7a0a6affd94f2d", - "reference": "2dc5431fd4fd84662615b435af7a0a6affd94f2d", + "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/d9b83e7132451dfddfa8ef398b50cfa88e490c21", + "reference": "d9b83e7132451dfddfa8ef398b50cfa88e490c21", "shasum": "" }, "require": { @@ -6457,7 +6457,7 @@ "type": "tidelift" } ], - "time": "2024-10-28T11:18:16+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/stopwatch", @@ -6783,16 +6783,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "a5d88e50935a998eb84495098f2d1e3aa75de627" + "reference": "e34839ab413e1dc32bd2cb9f95186af1bacaee7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/a5d88e50935a998eb84495098f2d1e3aa75de627", - "reference": "a5d88e50935a998eb84495098f2d1e3aa75de627", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e34839ab413e1dc32bd2cb9f95186af1bacaee7e", + "reference": "e34839ab413e1dc32bd2cb9f95186af1bacaee7e", "shasum": "" }, "require": { @@ -6873,7 +6873,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/twig-bridge/tree/v7.2.0-BETA2" }, "funding": [ { @@ -6889,7 +6889,7 @@ "type": "tidelift" } ], - "time": "2024-10-25T16:06:58+00:00" + "time": "2024-11-06T08:15:21+00:00" }, { "name": "symfony/twig-bundle", @@ -7137,12 +7137,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-autocomplete.git", - "reference": "c1681c9b8fc3aa09657e02b8842be69102918a89" + "reference": "899baeabb95b6d073324f74b82575f12c5dfebdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-autocomplete/zipball/c1681c9b8fc3aa09657e02b8842be69102918a89", - "reference": "c1681c9b8fc3aa09657e02b8842be69102918a89", + "url": "https://api.github.com/repos/symfony/ux-autocomplete/zipball/899baeabb95b6d073324f74b82575f12c5dfebdb", + "reference": "899baeabb95b6d073324f74b82575f12c5dfebdb", "shasum": "" }, "require": { @@ -7220,7 +7220,7 @@ "type": "tidelift" } ], - "time": "2024-10-24T09:16:33+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-chartjs", @@ -7228,12 +7228,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-chartjs.git", - "reference": "70ff570d96812487c523afd5756df671ec5c5cee" + "reference": "4c1039f35de42f398330439d612ecef361e818cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-chartjs/zipball/70ff570d96812487c523afd5756df671ec5c5cee", - "reference": "70ff570d96812487c523afd5756df671ec5c5cee", + "url": "https://api.github.com/repos/symfony/ux-chartjs/zipball/4c1039f35de42f398330439d612ecef361e818cc", + "reference": "4c1039f35de42f398330439d612ecef361e818cc", "shasum": "" }, "require": { @@ -7285,7 +7285,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-chartjs/tree/v2.21.0" + "source": "https://github.com/symfony/ux-chartjs/tree/2.x" }, "funding": [ { @@ -7301,7 +7301,7 @@ "type": "tidelift" } ], - "time": "2024-10-15T10:36:49+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-cropperjs", @@ -7309,12 +7309,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-cropperjs.git", - "reference": "fa8dd0f4fdac8f216206aa06d2e5d771fbb57b83" + "reference": "82e0a09708cd98cb447af80593a6dc958d516c97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-cropperjs/zipball/fa8dd0f4fdac8f216206aa06d2e5d771fbb57b83", - "reference": "fa8dd0f4fdac8f216206aa06d2e5d771fbb57b83", + "url": "https://api.github.com/repos/symfony/ux-cropperjs/zipball/82e0a09708cd98cb447af80593a6dc958d516c97", + "reference": "82e0a09708cd98cb447af80593a6dc958d516c97", "shasum": "" }, "require": { @@ -7371,7 +7371,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-cropperjs/tree/v2.21.0" + "source": "https://github.com/symfony/ux-cropperjs/tree/2.x" }, "funding": [ { @@ -7387,7 +7387,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-dropzone", @@ -7395,12 +7395,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-dropzone.git", - "reference": "ad7889144bb245665c894f63bd732f3927d8e4a1" + "reference": "57be8d1a2381099bddd5bd61e16278e7bcfc2d4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-dropzone/zipball/ad7889144bb245665c894f63bd732f3927d8e4a1", - "reference": "ad7889144bb245665c894f63bd732f3927d8e4a1", + "url": "https://api.github.com/repos/symfony/ux-dropzone/zipball/57be8d1a2381099bddd5bd61e16278e7bcfc2d4b", + "reference": "57be8d1a2381099bddd5bd61e16278e7bcfc2d4b", "shasum": "" }, "require": { @@ -7451,7 +7451,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-dropzone/tree/v2.21.0" + "source": "https://github.com/symfony/ux-dropzone/tree/2.x" }, "funding": [ { @@ -7467,7 +7467,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-icons", @@ -7565,12 +7565,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-lazy-image.git", - "reference": "6eddf3a6747fa108cd6115e55b51faa62ddfe977" + "reference": "ce8f1bcaa32ed90651a87509ab506edfa7e56d39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-lazy-image/zipball/6eddf3a6747fa108cd6115e55b51faa62ddfe977", - "reference": "6eddf3a6747fa108cd6115e55b51faa62ddfe977", + "url": "https://api.github.com/repos/symfony/ux-lazy-image/zipball/ce8f1bcaa32ed90651a87509ab506edfa7e56d39", + "reference": "ce8f1bcaa32ed90651a87509ab506edfa7e56d39", "shasum": "" }, "require": { @@ -7621,7 +7621,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-lazy-image/tree/v2.21.0" + "source": "https://github.com/symfony/ux-lazy-image/tree/2.x" }, "funding": [ { @@ -7637,7 +7637,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-leaflet-map", @@ -7645,12 +7645,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-leaflet-map.git", - "reference": "7f2b9a96d8fe7435c462608dabedeab6deb66725" + "reference": "6feb25289443550f26e658300c1f1b89abbecdbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-leaflet-map/zipball/7f2b9a96d8fe7435c462608dabedeab6deb66725", - "reference": "7f2b9a96d8fe7435c462608dabedeab6deb66725", + "url": "https://api.github.com/repos/symfony/ux-leaflet-map/zipball/6feb25289443550f26e658300c1f1b89abbecdbb", + "reference": "6feb25289443550f26e658300c1f1b89abbecdbb", "shasum": "" }, "require": { @@ -7691,7 +7691,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-leaflet-map/tree/v2.21.0" + "source": "https://github.com/symfony/ux-leaflet-map/tree/2.x" }, "funding": [ { @@ -7707,7 +7707,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:22:09+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-live-component", @@ -7715,12 +7715,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-live-component.git", - "reference": "b1727573b4bff5821958306c6360668aac82f6d3" + "reference": "ef73cff1bc8c1d5736f549733143bbf3c29cf54c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/b1727573b4bff5821958306c6360668aac82f6d3", - "reference": "b1727573b4bff5821958306c6360668aac82f6d3", + "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/ef73cff1bc8c1d5736f549733143bbf3c29cf54c", + "reference": "ef73cff1bc8c1d5736f549733143bbf3c29cf54c", "shasum": "" }, "require": { @@ -7802,7 +7802,7 @@ "type": "tidelift" } ], - "time": "2024-10-31T16:39:49+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-map", @@ -7810,12 +7810,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-map.git", - "reference": "ecbf1b35928040033841cab059b40a88643f8743" + "reference": "25185ff4b3157bac64af794f72debb7ed082ef74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-map/zipball/ecbf1b35928040033841cab059b40a88643f8743", - "reference": "ecbf1b35928040033841cab059b40a88643f8743", + "url": "https://api.github.com/repos/symfony/ux-map/zipball/25185ff4b3157bac64af794f72debb7ed082ef74", + "reference": "25185ff4b3157bac64af794f72debb7ed082ef74", "shasum": "" }, "require": { @@ -7869,7 +7869,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-map/tree/v2.21.0" + "source": "https://github.com/symfony/ux-map/tree/2.x" }, "funding": [ { @@ -7885,7 +7885,7 @@ "type": "tidelift" } ], - "time": "2024-10-15T10:36:49+00:00" + "time": "2024-11-04T18:32:35+00:00" }, { "name": "symfony/ux-notify", @@ -7893,12 +7893,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-notify.git", - "reference": "082283e52a85e18cf46c39d2974ccd7370853ab6" + "reference": "88cdccb64a10fa56c4fb44c85eb19c8039cc8c5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-notify/zipball/082283e52a85e18cf46c39d2974ccd7370853ab6", - "reference": "082283e52a85e18cf46c39d2974ccd7370853ab6", + "url": "https://api.github.com/repos/symfony/ux-notify/zipball/88cdccb64a10fa56c4fb44c85eb19c8039cc8c5e", + "reference": "88cdccb64a10fa56c4fb44c85eb19c8039cc8c5e", "shasum": "" }, "require": { @@ -7952,7 +7952,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-notify/tree/v2.21.0" + "source": "https://github.com/symfony/ux-notify/tree/2.x" }, "funding": [ { @@ -7968,7 +7968,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-react", @@ -7976,12 +7976,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-react.git", - "reference": "1e8f097e73f6d561272b044cb3a7b5ab84eda3ce" + "reference": "b44072846cd1700c5f61a69a55a3bb086d786fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-react/zipball/1e8f097e73f6d561272b044cb3a7b5ab84eda3ce", - "reference": "1e8f097e73f6d561272b044cb3a7b5ab84eda3ce", + "url": "https://api.github.com/repos/symfony/ux-react/zipball/b44072846cd1700c5f61a69a55a3bb086d786fdb", + "reference": "b44072846cd1700c5f61a69a55a3bb086d786fdb", "shasum": "" }, "require": { @@ -8029,7 +8029,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-react/tree/v2.21.0" + "source": "https://github.com/symfony/ux-react/tree/2.x" }, "funding": [ { @@ -8045,7 +8045,7 @@ "type": "tidelift" } ], - "time": "2024-10-22T14:52:13+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-svelte", @@ -8053,12 +8053,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-svelte.git", - "reference": "4ee061583e39f5b2356a376ee213a8c49d0dda30" + "reference": "5c91954115f6708d9818dd8568ab534c89656980" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-svelte/zipball/4ee061583e39f5b2356a376ee213a8c49d0dda30", - "reference": "4ee061583e39f5b2356a376ee213a8c49d0dda30", + "url": "https://api.github.com/repos/symfony/ux-svelte/zipball/5c91954115f6708d9818dd8568ab534c89656980", + "reference": "5c91954115f6708d9818dd8568ab534c89656980", "shasum": "" }, "require": { @@ -8110,7 +8110,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-svelte/tree/v2.21.0" + "source": "https://github.com/symfony/ux-svelte/tree/2.x" }, "funding": [ { @@ -8126,7 +8126,7 @@ "type": "tidelift" } ], - "time": "2024-10-15T10:36:49+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-swup", @@ -8134,12 +8134,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-swup.git", - "reference": "d3661dcfe2a0555bd97f799d6d0d3d31f3a7f462" + "reference": "0d43a8b8f2adbeed010ce8dc69a2a553f5efc5df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-swup/zipball/d3661dcfe2a0555bd97f799d6d0d3d31f3a7f462", - "reference": "d3661dcfe2a0555bd97f799d6d0d3d31f3a7f462", + "url": "https://api.github.com/repos/symfony/ux-swup/zipball/0d43a8b8f2adbeed010ce8dc69a2a553f5efc5df", + "reference": "0d43a8b8f2adbeed010ce8dc69a2a553f5efc5df", "shasum": "" }, "conflict": { @@ -8178,7 +8178,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-swup/tree/v2.21.0" + "source": "https://github.com/symfony/ux-swup/tree/2.x" }, "funding": [ { @@ -8194,7 +8194,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-toggle-password", @@ -8202,12 +8202,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-toggle-password.git", - "reference": "48d4aa13c3286849c4d86e03df9c5b90917e4d15" + "reference": "22aaa245e8439ac55267fc6c9d056f60663fff0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-toggle-password/zipball/48d4aa13c3286849c4d86e03df9c5b90917e4d15", - "reference": "48d4aa13c3286849c4d86e03df9c5b90917e4d15", + "url": "https://api.github.com/repos/symfony/ux-toggle-password/zipball/22aaa245e8439ac55267fc6c9d056f60663fff0f", + "reference": "22aaa245e8439ac55267fc6c9d056f60663fff0f", "shasum": "" }, "require": { @@ -8259,7 +8259,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-toggle-password/tree/v2.21.0" + "source": "https://github.com/symfony/ux-toggle-password/tree/2.x" }, "funding": [ { @@ -8275,7 +8275,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-translator", @@ -8283,12 +8283,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-translator.git", - "reference": "df523d5f90256a40bc7ceaabfe6664bd9856cb74" + "reference": "461f1a2aa1db6e525550b7ce4ccc4bc649938733" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-translator/zipball/df523d5f90256a40bc7ceaabfe6664bd9856cb74", - "reference": "df523d5f90256a40bc7ceaabfe6664bd9856cb74", + "url": "https://api.github.com/repos/symfony/ux-translator/zipball/461f1a2aa1db6e525550b7ce4ccc4bc649938733", + "reference": "461f1a2aa1db6e525550b7ce4ccc4bc649938733", "shasum": "" }, "require": { @@ -8336,7 +8336,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-translator/tree/v2.21.0" + "source": "https://github.com/symfony/ux-translator/tree/2.x" }, "funding": [ { @@ -8352,7 +8352,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-turbo", @@ -8360,12 +8360,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-turbo.git", - "reference": "add0a143c032a482c07c8d5e8776270973491abd" + "reference": "418f639e3aab5b1b68cd92fad558db53ed90484f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/add0a143c032a482c07c8d5e8776270973491abd", - "reference": "add0a143c032a482c07c8d5e8776270973491abd", + "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/418f639e3aab5b1b68cd92fad558db53ed90484f", + "reference": "418f639e3aab5b1b68cd92fad558db53ed90484f", "shasum": "" }, "require": { @@ -8451,7 +8451,7 @@ "type": "tidelift" } ], - "time": "2024-10-30T20:05:58+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-twig-component", @@ -8459,12 +8459,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-twig-component.git", - "reference": "da12467494cbf4adc91384f7ace7063e315b7445" + "reference": "cb2fc0f55ad66e961b3af3706bddbab5f4053aaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/da12467494cbf4adc91384f7ace7063e315b7445", - "reference": "da12467494cbf4adc91384f7ace7063e315b7445", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/cb2fc0f55ad66e961b3af3706bddbab5f4053aaa", + "reference": "cb2fc0f55ad66e961b3af3706bddbab5f4053aaa", "shasum": "" }, "require": { @@ -8535,7 +8535,7 @@ "type": "tidelift" } ], - "time": "2024-11-01T06:57:32+00:00" + "time": "2024-11-04T01:08:49+00:00" }, { "name": "symfony/ux-typed", @@ -8543,12 +8543,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-typed.git", - "reference": "6c79f083bbca3a3d0663387493874077e16a5dd7" + "reference": "14c2ee2d5ce0ff5b2a5b15e907be7171924b7907" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-typed/zipball/6c79f083bbca3a3d0663387493874077e16a5dd7", - "reference": "6c79f083bbca3a3d0663387493874077e16a5dd7", + "url": "https://api.github.com/repos/symfony/ux-typed/zipball/14c2ee2d5ce0ff5b2a5b15e907be7171924b7907", + "reference": "14c2ee2d5ce0ff5b2a5b15e907be7171924b7907", "shasum": "" }, "conflict": { @@ -8587,7 +8587,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-typed/tree/v2.21.0" + "source": "https://github.com/symfony/ux-typed/tree/2.x" }, "funding": [ { @@ -8603,7 +8603,7 @@ "type": "tidelift" } ], - "time": "2024-10-12T06:22:44+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/ux-vue", @@ -8611,12 +8611,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/ux-vue.git", - "reference": "8acdb434eaf653ab9e8fd9a787becc3fd6d3a7eb" + "reference": "20150d5ad63dd3a692dd950b1a2bef3bfd2a3259" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-vue/zipball/8acdb434eaf653ab9e8fd9a787becc3fd6d3a7eb", - "reference": "8acdb434eaf653ab9e8fd9a787becc3fd6d3a7eb", + "url": "https://api.github.com/repos/symfony/ux-vue/zipball/20150d5ad63dd3a692dd950b1a2bef3bfd2a3259", + "reference": "20150d5ad63dd3a692dd950b1a2bef3bfd2a3259", "shasum": "" }, "require": { @@ -8668,7 +8668,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-vue/tree/v2.21.0" + "source": "https://github.com/symfony/ux-vue/tree/2.x" }, "funding": [ { @@ -8684,20 +8684,20 @@ "type": "tidelift" } ], - "time": "2024-10-15T10:36:49+00:00" + "time": "2024-11-02T19:57:29+00:00" }, { "name": "symfony/validator", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "8392b9bafbfed3c166a979ac0bd8a3186abb8e75" + "reference": "20bf8bec7938be121e76dd9a80aac4c19ceb6318" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/8392b9bafbfed3c166a979ac0bd8a3186abb8e75", - "reference": "8392b9bafbfed3c166a979ac0bd8a3186abb8e75", + "url": "https://api.github.com/repos/symfony/validator/zipball/20bf8bec7938be121e76dd9a80aac4c19ceb6318", + "reference": "20bf8bec7938be121e76dd9a80aac4c19ceb6318", "shasum": "" }, "require": { @@ -8765,7 +8765,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/validator/tree/v7.2.0-BETA2" }, "funding": [ { @@ -8781,20 +8781,20 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2024-11-04T11:36:24+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "b86ce1b5bb196cfb3796856979167271d3989c7c" + "reference": "131a71f779b76fefc41465f1ccbe701a02b4389b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b86ce1b5bb196cfb3796856979167271d3989c7c", - "reference": "b86ce1b5bb196cfb3796856979167271d3989c7c", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/131a71f779b76fefc41465f1ccbe701a02b4389b", + "reference": "131a71f779b76fefc41465f1ccbe701a02b4389b", "shasum": "" }, "require": { @@ -8848,7 +8848,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/var-dumper/tree/v7.2.0-BETA2" }, "funding": [ { @@ -8864,7 +8864,7 @@ "type": "tidelift" } ], - "time": "2024-10-23T08:11:15+00:00" + "time": "2024-11-05T15:35:02+00:00" }, { "name": "symfony/var-exporter", @@ -11925,16 +11925,16 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "078398ebac9b707438286e8d689b30b5ef1e6602" + "reference": "0228dd1180ee3ef6c85eeb51ddbe89e0eaef7d33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/078398ebac9b707438286e8d689b30b5ef1e6602", - "reference": "078398ebac9b707438286e8d689b30b5ef1e6602", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/0228dd1180ee3ef6c85eeb51ddbe89e0eaef7d33", + "reference": "0228dd1180ee3ef6c85eeb51ddbe89e0eaef7d33", "shasum": "" }, "require": { @@ -11987,7 +11987,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.2.0-BETA2" }, "funding": [ { @@ -12003,20 +12003,20 @@ "type": "tidelift" } ], - "time": "2024-10-23T06:50:56+00:00" + "time": "2024-10-27T06:46:44+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v7.2.0-BETA1", + "version": "v7.2.0-BETA2", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "1827c2cf600a760334b4fbbc610a9fe308a3f73a" + "reference": "d4e008e21cbbc03a992edeecf49c9bbfd3a4f837" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/1827c2cf600a760334b4fbbc610a9fe308a3f73a", - "reference": "1827c2cf600a760334b4fbbc610a9fe308a3f73a", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/d4e008e21cbbc03a992edeecf49c9bbfd3a4f837", + "reference": "d4e008e21cbbc03a992edeecf49c9bbfd3a4f837", "shasum": "" }, "require": { @@ -12069,7 +12069,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.2.0-BETA1" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.2.0-BETA2" }, "funding": [ { @@ -12085,7 +12085,7 @@ "type": "tidelift" } ], - "time": "2024-10-23T08:11:15+00:00" + "time": "2024-11-05T15:35:02+00:00" }, { "name": "theseer/tokenizer", @@ -12336,16 +12336,16 @@ }, { "name": "zenstruck/browser", - "version": "v1.9.0", + "version": "v1.9.1", "source": { "type": "git", "url": "https://github.com/zenstruck/browser.git", - "reference": "9603f3dab8377ae3b341e653a8e61e15734b6336" + "reference": "a1518531749b157347de60eef2a0a6f5fbd97b97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/browser/zipball/9603f3dab8377ae3b341e653a8e61e15734b6336", - "reference": "9603f3dab8377ae3b341e653a8e61e15734b6336", + "url": "https://api.github.com/repos/zenstruck/browser/zipball/a1518531749b157347de60eef2a0a6f5fbd97b97", + "reference": "a1518531749b157347de60eef2a0a6f5fbd97b97", "shasum": "" }, "require": { @@ -12398,7 +12398,7 @@ ], "support": { "issues": "https://github.com/zenstruck/browser/issues", - "source": "https://github.com/zenstruck/browser/tree/v1.9.0" + "source": "https://github.com/zenstruck/browser/tree/v1.9.1" }, "funding": [ { @@ -12406,7 +12406,7 @@ "type": "github" } ], - "time": "2024-10-20T23:04:59+00:00" + "time": "2024-11-05T12:21:53+00:00" }, { "name": "zenstruck/callback", @@ -12466,16 +12466,16 @@ }, { "name": "zenstruck/foundry", - "version": "v2.2.1", + "version": "v2.2.2", "source": { "type": "git", "url": "https://github.com/zenstruck/foundry.git", - "reference": "4743a9da142b42d484ac7a99c1a7068aa66c7bec" + "reference": "44eec45b620fd5419906c387512bd1acdf898647" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/foundry/zipball/4743a9da142b42d484ac7a99c1a7068aa66c7bec", - "reference": "4743a9da142b42d484ac7a99c1a7068aa66c7bec", + "url": "https://api.github.com/repos/zenstruck/foundry/zipball/44eec45b620fd5419906c387512bd1acdf898647", + "reference": "44eec45b620fd5419906c387512bd1acdf898647", "shasum": "" }, "require": { @@ -12555,7 +12555,7 @@ ], "support": { "issues": "https://github.com/zenstruck/foundry/issues", - "source": "https://github.com/zenstruck/foundry/tree/v2.2.1" + "source": "https://github.com/zenstruck/foundry/tree/v2.2.2" }, "funding": [ { @@ -12563,7 +12563,7 @@ "type": "github" } ], - "time": "2024-10-31T12:10:58+00:00" + "time": "2024-11-05T16:39:17+00:00" } ], "aliases": [], From a422be1a02f931322f21bc537f25241d8425550e Mon Sep 17 00:00:00 2001 From: matlec Date: Wed, 6 Nov 2024 21:44:36 +0100 Subject: [PATCH 23/42] [StimulusBundle][Doc] Mention `removeComments` will no longer be necessary --- src/StimulusBundle/doc/index.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/StimulusBundle/doc/index.rst b/src/StimulusBundle/doc/index.rst index 745c19bc0a4..4188b2f22b0 100644 --- a/src/StimulusBundle/doc/index.rst +++ b/src/StimulusBundle/doc/index.rst @@ -157,8 +157,9 @@ To make a third-party controller lazy, in ``assets/controllers.json``, set .. note:: - If you write your controllers using TypeScript, make sure - ``removeComments`` is not set to ``true`` in your TypeScript config. + If you write your controllers using TypeScript and you're using + StimulusBundle ≀ 2.21.0, make sure ``removeComments`` is not set + to ``true`` in your TypeScript config. Stimulus Tools around the World ------------------------------- From 4feaeb07296c5e7856a5f65d808e1eb576400a60 Mon Sep 17 00:00:00 2001 From: matlec Date: Wed, 6 Nov 2024 21:55:06 +0100 Subject: [PATCH 24/42] [Autocomplete][Doc] Mention `preload` can be set to `false` --- src/Autocomplete/doc/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Autocomplete/doc/index.rst b/src/Autocomplete/doc/index.rst index 35baf134a01..d9dd23c4c7d 100644 --- a/src/Autocomplete/doc/index.rst +++ b/src/Autocomplete/doc/index.rst @@ -272,6 +272,7 @@ to the options above, you can also pass: ``preload`` (default: ``focus``) Set to ``focus`` to call the ``load`` function when control receives focus. Set to ``true`` to call the ``load`` upon control initialization (with an empty search). + Set to ``false`` not to call the ``load`` function when control receives focus. ``extra_options`` (default ``[]``) Allow you to pass extra options for Ajax-based autocomplete fields. From 11342b4ebf0e7031a848c93302bcf5afa0739431 Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Thu, 7 Nov 2024 10:21:01 +0100 Subject: [PATCH 25/42] [Test] Check for peerDependencies/symfony.importmap homogeneity, cleanup changes when a peerDependency changed because multiple versions --- bin/test_package.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bin/test_package.sh b/bin/test_package.sh index 669e293c949..d5fc420aa6e 100755 --- a/bin/test_package.sh +++ b/bin/test_package.sh @@ -47,6 +47,19 @@ processWorkspace() { fi echo -e "Processing workspace $workspace at location $location...\n" + + echo "Checking '$package_json_path' for peerDependencies and importmap dependencies to have the same version" + deps=$(jq -r '.peerDependencies | keys[]' "$package_json_path") + for library in $deps; do + version=$(jq -r ".peerDependencies.\"$library\"" "$package_json_path") + importmap_version=$(jq -r ".symfony.importmap.\"$library\"" "$package_json_path") + + if [ "$version" != "$importmap_version" ]; then + echo " -> Version mismatch for $library: $version (peerDependencies) vs $importmap_version (importmap)" + echo " -> You need to match the version of the \"peerDependency\" with the version in the \"importmap\"" + exit + fi + done echo "Checking '$package_json_path' for peerDependencies with multiple versions defined" deps_with_multiple_versions=$(jq -r '.peerDependencies | to_entries[] | select(.value | contains("||")) | .key' "$package_json_path") @@ -68,6 +81,9 @@ processWorkspace() { runTestSuite fi done + + echo " -> Reverting version changes for $library" + yarn workspace "$workspace" add "$library@$versionValue" --peer done else echo -e " -> No peerDependencies found with multiple versions defined\n" From 3664af5d5d51a3c750dbc57afde786efc674c6f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Thu, 7 Nov 2024 18:26:30 +0100 Subject: [PATCH 26/42] CS fix --- src/TwigComponent/src/Command/TwigComponentDebugCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php index 68be2f29f2a..3b224ca5a7d 100644 --- a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php +++ b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php @@ -187,7 +187,7 @@ private function findAnonymousComponents(): array $path = $template->getPath(); if ($template->getRelativePath()) { - $path = \rtrim(\substr($template->getPath(), 0, -1 * \strlen($template->getRelativePath())), \DIRECTORY_SEPARATOR); ++ $path = rtrim(substr($template->getPath(), 0, -1 * \strlen($template->getRelativePath())), \DIRECTORY_SEPARATOR); } if (isset($dirs[$path]) && FilesystemLoader::MAIN_NAMESPACE !== $dirs[$path]) { From 41d9df084aa24138736c09e3577e938e8d2c3436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Thu, 7 Nov 2024 18:27:40 +0100 Subject: [PATCH 27/42] Fix copy/paste error --- src/TwigComponent/src/Command/TwigComponentDebugCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php index 3b224ca5a7d..843138026c6 100644 --- a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php +++ b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php @@ -187,7 +187,7 @@ private function findAnonymousComponents(): array $path = $template->getPath(); if ($template->getRelativePath()) { -+ $path = rtrim(substr($template->getPath(), 0, -1 * \strlen($template->getRelativePath())), \DIRECTORY_SEPARATOR); + $path = rtrim(substr($template->getPath(), 0, -1 * \strlen($template->getRelativePath())), \DIRECTORY_SEPARATOR); } if (isset($dirs[$path]) && FilesystemLoader::MAIN_NAMESPACE !== $dirs[$path]) { From 218c00009e43818b9bc06551c34c1f6351382e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Thu, 7 Nov 2024 18:20:47 +0100 Subject: [PATCH 28/42] [Icons] Group icons fetching per prefix --- src/Icons/src/Iconify.php | 48 ++++++++++++++++++++ src/Icons/tests/Unit/IconifyTest.php | 66 ++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/Icons/src/Iconify.php b/src/Icons/src/Iconify.php index 757dacb245c..e29f2c69f5c 100644 --- a/src/Icons/src/Iconify.php +++ b/src/Icons/src/Iconify.php @@ -85,6 +85,54 @@ public function fetchIcon(string $prefix, string $name): Icon ]); } + public function fetchIcons(string $prefix, array $names): array + { + if (!isset($this->sets()[$prefix])) { + throw new IconNotFoundException(\sprintf('The icon set "%s" does not exist on iconify.design.', $prefix)); + } + + // Sort to enforce cache hits + sort($names); + $queryString = implode(',', $names); + if (!preg_match('#^[a-z0-9-,]+$#', $queryString)) { + throw new \InvalidArgumentException('Invalid icon names.'); + } + + // URL must be 500 chars max (iconify limit) + // -39 chars: https://api.iconify.design/XXX.json?icons= + // -safe margin + if (450 < \strlen($prefix.$queryString)) { + throw new \InvalidArgumentException('The query string is too long.'); + } + + $response = $this->http->request('GET', \sprintf('/%s.json', $prefix), [ + 'headers' => [ + 'Accept' => 'application/json', + ], + 'query' => [ + 'icons' => strtolower($queryString), + ], + ]); + + if (200 !== $response->getStatusCode()) { + throw new IconNotFoundException(\sprintf('The icon set "%s" does not exist on iconify.design.', $prefix)); + } + + $data = $response->toArray(); + + $icons = []; + foreach ($data['icons'] as $iconName => $iconData) { + $height = $iconData['height'] ?? $data['height'] ??= $this->sets()[$prefix]['height'] ?? null; + $width = $iconData['width'] ?? $data['width'] ??= $this->sets()[$prefix]['width'] ?? null; + + $icons[$iconName] = new Icon($iconData['body'], [ + 'viewBox' => \sprintf('0 0 %d %d', $width ?? $height, $height ?? $width), + ]); + } + + return $icons; + } + public function hasIconSet(string $prefix): bool { return isset($this->sets()[$prefix]); diff --git a/src/Icons/tests/Unit/IconifyTest.php b/src/Icons/tests/Unit/IconifyTest.php index b940683660e..3fafce3abcc 100644 --- a/src/Icons/tests/Unit/IconifyTest.php +++ b/src/Icons/tests/Unit/IconifyTest.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; use Symfony\UX\Icons\Exception\IconNotFoundException; +use Symfony\UX\Icons\Icon; use Symfony\UX\Icons\Iconify; /** @@ -162,6 +163,71 @@ public function testFetchIconThrowsWhenStatusCodeNot200(): void $iconify->fetchIcon('bi', 'heart'); } + public function testFetchIcons(): void + { + $iconify = new Iconify( + cache: new NullAdapter(), + endpoint: 'https://example.com', + http: new MockHttpClient([ + new JsonMockResponse([ + 'bi' => [], + ]), + new JsonMockResponse([ + 'icons' => [ + 'heart' => [ + 'body' => '', + 'height' => 17, + ], + 'bar' => [ + 'body' => '', + 'height' => 17, + ], + ], + ]), + ]), + ); + + $icons = $iconify->fetchIcons('bi', ['heart', 'bar']); + + $this->assertCount(2, $icons); + $this->assertSame(['heart', 'bar'], array_keys($icons)); + $this->assertContainsOnlyInstancesOf(Icon::class, $icons); + } + + public function testFetchIconsThrowsWithInvalidIconNames(): void + { + $iconify = new Iconify( + cache: new NullAdapter(), + endpoint: 'https://example.com', + http: new MockHttpClient([ + new JsonMockResponse([ + 'bi' => [], + ]), + ]), + ); + + $this->expectException(\InvalidArgumentException::class); + + $iconify->fetchIcons('bi', ['Γ ', 'foo']); + } + + public function testFetchIconsThrowsWithTooManyIcons(): void + { + $iconify = new Iconify( + cache: new NullAdapter(), + endpoint: 'https://example.com', + http: new MockHttpClient([ + new JsonMockResponse([ + 'bi' => [], + ]), + ]), + ); + + $this->expectException(\InvalidArgumentException::class); + + $iconify->fetchIcons('bi', array_fill(0, 50, '1234567890')); + } + public function testGetMetadata(): void { $responseFile = __DIR__.'/../Fixtures/Iconify/collections.json'; From eece91cc06bb3a0c01eed8ed11afecc543486878 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Sat, 9 Nov 2024 09:26:22 -0500 Subject: [PATCH 29/42] [Site] fix typo on cookbook index --- ux.symfony.com/templates/cookbook/index.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ux.symfony.com/templates/cookbook/index.html.twig b/ux.symfony.com/templates/cookbook/index.html.twig index 2a18a9f36ac..a15a44139c7 100644 --- a/ux.symfony.com/templates/cookbook/index.html.twig +++ b/ux.symfony.com/templates/cookbook/index.html.twig @@ -3,7 +3,7 @@ {% set meta = { title: 'Cookbook', title_suffix: ' - Symfony UX', - description: 'Symfony UX cookbook - Concrete exeample to understantd all the concepts and components of Symfony UX', + description: 'Symfony UX Cookbook - Concrete examples to understantd all the concepts and components of Symfony UX.', canonical: url('app_cookbook'), } %} From 9ac91b842e9f3ff211034d1f705ee1540627b5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sat, 9 Nov 2024 23:32:39 +0100 Subject: [PATCH 30/42] [Icons] Support aliases in LockIconsCommand --- src/Icons/src/Command/LockIconsCommand.php | 16 ++++++++++++---- .../src/DependencyInjection/UXIconsExtension.php | 5 +++++ src/Icons/tests/Fixtures/TestKernel.php | 4 ++++ .../Integration/Command/LockIconsCommandTest.php | 14 +++++++++++--- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/Icons/src/Command/LockIconsCommand.php b/src/Icons/src/Command/LockIconsCommand.php index c3b3d2fa65a..69fab8e971b 100644 --- a/src/Icons/src/Command/LockIconsCommand.php +++ b/src/Icons/src/Command/LockIconsCommand.php @@ -37,6 +37,8 @@ public function __construct( private Iconify $iconify, private LocalSvgIconRegistry $registry, private IconFinder $iconFinder, + private readonly array $iconAliases = [], + private readonly array $iconSetAliases = [], ) { parent::__construct(); } @@ -59,19 +61,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int $count = 0; $io->comment('Scanning project for icons...'); + $finderIcons = $this->iconFinder->icons(); - foreach ($this->iconFinder->icons() as $icon) { + if ($this->iconAliases) { + $io->comment('Adding icons aliases...'); + } + + foreach ([...array_values($this->iconAliases), ...array_values($finderIcons)] as $icon) { if (2 !== \count($parts = explode(':', $icon))) { continue; } - if (!$force && $this->registry->has($icon)) { + [$prefix, $name] = $parts; + $prefix = $this->iconSetAliases[$prefix] ?? $prefix; + + if (!$force && $this->registry->has($prefix.':'.$name)) { // icon already imported continue; } - [$prefix, $name] = $parts; - if (!$this->iconify->hasIconSet($prefix)) { // not an icon set? example: "og:twitter" if ($io->isVeryVerbose()) { diff --git a/src/Icons/src/DependencyInjection/UXIconsExtension.php b/src/Icons/src/DependencyInjection/UXIconsExtension.php index 618749ee701..81042277976 100644 --- a/src/Icons/src/DependencyInjection/UXIconsExtension.php +++ b/src/Icons/src/DependencyInjection/UXIconsExtension.php @@ -178,6 +178,11 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container } } + $container->getDefinition('.ux_icons.command.lock') + ->setArgument(3, $mergedConfig['aliases']) + ->setArgument(4, $iconSetAliases) + ; + if (!$container->getParameter('kernel.debug')) { $container->removeDefinition('.ux_icons.command.import'); } diff --git a/src/Icons/tests/Fixtures/TestKernel.php b/src/Icons/tests/Fixtures/TestKernel.php index 6a9d0f0bdb0..2f573439dd4 100644 --- a/src/Icons/tests/Fixtures/TestKernel.php +++ b/src/Icons/tests/Fixtures/TestKernel.php @@ -60,6 +60,10 @@ protected function configureContainer(ContainerConfigurator $container): void $container->extension('ux_icons', [ 'icon_dir' => '%kernel.project_dir%/tests/Fixtures/icons', + 'aliases' => [ + 'foo' => 'lucide:circle', + 'bar' => 'lu:circle-off', + ], 'icon_sets' => [ 'fla' => [ 'path' => '%kernel.project_dir%/tests/Fixtures/images/flags', diff --git a/src/Icons/tests/Integration/Command/LockIconsCommandTest.php b/src/Icons/tests/Integration/Command/LockIconsCommandTest.php index f6b2e11f2d4..abcfc45fdf6 100644 --- a/src/Icons/tests/Integration/Command/LockIconsCommandTest.php +++ b/src/Icons/tests/Integration/Command/LockIconsCommandTest.php @@ -25,6 +25,8 @@ final class LockIconsCommandTest extends KernelTestCase private const ICONS = [ __DIR__.'/../../Fixtures/icons/iconamoon/3d-duotone.svg', __DIR__.'/../../Fixtures/icons/flag/eu-4x3.svg', + __DIR__.'/../../Fixtures/icons/lucide/circle.svg', + __DIR__.'/../../Fixtures/icons/lucide/circle-off.svg', ]; /** @@ -50,9 +52,11 @@ public function testImportFoundIcons(): void $this->executeConsoleCommand('ux:icons:lock') ->assertSuccessful() ->assertOutputContains('Scanning project for icons...') + ->assertOutputContains('Imported lucide:circle') + ->assertOutputContains('Imported lucide:circle-off') ->assertOutputContains('Imported flag:eu-4x3') ->assertOutputContains('Imported iconamoon:3d-duotone') - ->assertOutputContains('Imported 2 icons') + ->assertOutputContains('Imported 4 icons') ; foreach (self::ICONS as $icon) { @@ -70,17 +74,21 @@ public function testForceImportFoundIcons(): void $this->executeConsoleCommand('ux:icons:lock') ->assertSuccessful() ->assertOutputContains('Scanning project for icons...') + ->assertOutputContains('Imported lucide:circle') + ->assertOutputContains('Imported lucide:circle-off') ->assertOutputContains('Imported flag:eu-4x3') ->assertOutputContains('Imported iconamoon:3d-duotone') - ->assertOutputContains('Imported 2 icons') + ->assertOutputContains('Imported 4 icons') ; $this->executeConsoleCommand('ux:icons:lock --force') ->assertSuccessful() ->assertOutputContains('Scanning project for icons...') + ->assertOutputContains('Imported lucide:circle') + ->assertOutputContains('Imported lucide:circle-off') ->assertOutputContains('Imported flag:eu-4x3') ->assertOutputContains('Imported iconamoon:3d-duotone') - ->assertOutputContains('Imported 2 icons') + ->assertOutputContains('Imported 4 icons') ; } } From 88d24e0ee9b756434e1660b4d6414094c8ea33d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Fri, 8 Nov 2024 03:22:16 +0100 Subject: [PATCH 31/42] [Icons] Fetch icons in batch in Import command --- src/Icons/src/Command/ImportIconCommand.php | 81 ++++++++++++------- src/Icons/src/Iconify.php | 49 +++++++++-- .../Command/ImportIconCommandTest.php | 31 +++++-- src/Icons/tests/Unit/IconifyTest.php | 79 ++++++++++++++++++ 4 files changed, 202 insertions(+), 38 deletions(-) diff --git a/src/Icons/src/Command/ImportIconCommand.php b/src/Icons/src/Command/ImportIconCommand.php index f1c8a08b9fb..06b2354506c 100644 --- a/src/Icons/src/Command/ImportIconCommand.php +++ b/src/Icons/src/Command/ImportIconCommand.php @@ -18,7 +18,6 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\UX\Icons\Exception\IconNotFoundException; use Symfony\UX\Icons\Iconify; use Symfony\UX\Icons\Registry\LocalSvgIconRegistry; @@ -41,11 +40,7 @@ public function __construct(private Iconify $iconify, private LocalSvgIconRegist protected function configure(): void { $this - ->addArgument( - 'names', - InputArgument::IS_ARRAY | InputArgument::REQUIRED, - 'Icon name from ux.symfony.com/icons (e.g. "mdi:home")', - ) + ->addArgument('names', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Icon name from ux.symfony.com/icons (e.g. "mdi:home")') ; } @@ -54,7 +49,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io = new SymfonyStyle($input, $output); $names = $input->getArgument('names'); $result = Command::SUCCESS; + $importedIcons = 0; + $prefixIcons = []; foreach ($names as $name) { if (!preg_match('#^([\w-]+):([\w-]+)$#', $name, $matches)) { $io->error(\sprintf('Invalid icon name "%s".', $name)); @@ -63,35 +60,63 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } - [$fullName, $prefix, $name] = $matches; - - $io->comment(\sprintf('Importing %s...', $fullName)); + [, $prefix, $name] = $matches; + $prefixIcons[$prefix] ??= []; + $prefixIcons[$prefix][$name] = $name; + } - try { - $iconSvg = $this->iconify->fetchIcon($prefix, $name)->toHtml(); - } catch (IconNotFoundException $e) { - $io->error($e->getMessage()); + foreach ($prefixIcons as $prefix => $icons) { + if (!$this->iconify->hasIconSet($prefix)) { + $io->error(\sprintf('Icon set "%s" not found.', $prefix)); $result = Command::FAILURE; continue; } - $cursor = new Cursor($output); - $cursor->moveUp(2); - - $this->registry->add(\sprintf('%s/%s', $prefix, $name), $iconSvg); - - $license = $this->iconify->metadataFor($prefix)['license']; - - $io->text(\sprintf( - " βœ“ Imported %s:%s (License: %s). Render with: {{ ux_icon('%s') }}", - $prefix, - $name, - $license['url'] ?? '#', - $license['title'], - $fullName, - )); + $metadata = $this->iconify->metadataFor($prefix); $io->newLine(); + $io->writeln(\sprintf(' Icon set: %s (License: %s)', $metadata['name'], $metadata['license']['title'])); + + foreach ($this->iconify->chunk($prefix, array_keys($icons)) as $iconNames) { + $cursor = new Cursor($output); + foreach ($iconNames as $name) { + $io->writeln(\sprintf(' Importing %s:%s ...', $prefix, $name)); + } + $cursor->moveUp(\count($iconNames)); + + try { + $batchResults = $this->iconify->fetchIcons($prefix, $iconNames); + } catch (\InvalidArgumentException $e) { + // At this point no exception should be thrown + $io->error($e->getMessage()); + + return Command::FAILURE; + } + + foreach ($iconNames as $name) { + $cursor->clearLineAfter(); + + // If the icon is not found, the value will be null + if (null === $icon = $batchResults[$name] ?? null) { + $io->writeln(\sprintf(' βœ— Not Found %s:%s', $prefix, $name)); + + continue; + } + + ++$importedIcons; + $this->registry->add(\sprintf('%s/%s', $prefix, $name), (string) $icon); + $io->writeln(\sprintf(' βœ“ Imported %s:%s', $prefix, $name)); + } + } + } + + if ($importedIcons === $totalIcons = \count($names)) { + $io->success(\sprintf('Imported %d/%d icons.', $importedIcons, $totalIcons)); + } elseif ($importedIcons > 0) { + $io->warning(\sprintf('Imported %d/%d icons.', $importedIcons, $totalIcons)); + } else { + $io->error(\sprintf('Imported %d/%d icons.', $importedIcons, $totalIcons)); + $result = Command::FAILURE; } return $result; diff --git a/src/Icons/src/Iconify.php b/src/Icons/src/Iconify.php index e29f2c69f5c..892aa6fc18b 100644 --- a/src/Icons/src/Iconify.php +++ b/src/Icons/src/Iconify.php @@ -27,19 +27,27 @@ final class Iconify { public const API_ENDPOINT = 'https://api.iconify.design'; + // URL must be 500 chars max (iconify limit) + // -39 chars: https://api.iconify.design/XXX.json?icons= + // -safe margin + private const MAX_ICONS_QUERY_LENGTH = 400; + private HttpClientInterface $http; private \ArrayObject $sets; + private int $maxIconsQueryLength; public function __construct( private CacheInterface $cache, string $endpoint = self::API_ENDPOINT, ?HttpClientInterface $http = null, + ?int $maxIconsQueryLength = null, ) { if (!class_exists(HttpClient::class)) { throw new \LogicException('You must install "symfony/http-client" to use Iconify. Try running "composer require symfony/http-client".'); } $this->http = ScopingHttpClient::forBaseUri($http ?? HttpClient::create(), $endpoint); + $this->maxIconsQueryLength = min(self::MAX_ICONS_QUERY_LENGTH, $maxIconsQueryLength ?? self::MAX_ICONS_QUERY_LENGTH); } public function metadataFor(string $prefix): array @@ -95,13 +103,10 @@ public function fetchIcons(string $prefix, array $names): array sort($names); $queryString = implode(',', $names); if (!preg_match('#^[a-z0-9-,]+$#', $queryString)) { - throw new \InvalidArgumentException('Invalid icon names.'); + throw new \InvalidArgumentException('Invalid icon names.'.$queryString); } - // URL must be 500 chars max (iconify limit) - // -39 chars: https://api.iconify.design/XXX.json?icons= - // -safe margin - if (450 < \strlen($prefix.$queryString)) { + if (self::MAX_ICONS_QUERY_LENGTH < \strlen($prefix.$queryString)) { throw new \InvalidArgumentException('The query string is too long.'); } @@ -155,6 +160,40 @@ public function searchIcons(string $prefix, string $query) return new \ArrayObject($response->toArray()); } + /** + * @return iterable + */ + public function chunk(string $prefix, array $names): iterable + { + if (100 < ($prefixLength = \strlen($prefix))) { + throw new \InvalidArgumentException(\sprintf('The icon prefix "%s" is too long.', $prefix)); + } + + $maxLength = $this->maxIconsQueryLength - $prefixLength; + + $curBatch = []; + $curLength = 0; + foreach ($names as $name) { + if (100 < ($nameLength = \strlen($name))) { + throw new \InvalidArgumentException(\sprintf('The icon name "%s" is too long.', $name)); + } + if ($curLength && ($maxLength < ($curLength + $nameLength + 1))) { + yield $curBatch; + + $curBatch = []; + $curLength = 0; + } + $curLength += $nameLength + 1; + $curBatch[] = $name; + } + + if ($curLength) { + yield $curBatch; + } + + yield from []; + } + private function sets(): \ArrayObject { return $this->sets ??= $this->cache->get('ux-iconify-sets', function () { diff --git a/src/Icons/tests/Integration/Command/ImportIconCommandTest.php b/src/Icons/tests/Integration/Command/ImportIconCommandTest.php index b664ad453c7..0935fb4dd9a 100644 --- a/src/Icons/tests/Integration/Command/ImportIconCommandTest.php +++ b/src/Icons/tests/Integration/Command/ImportIconCommandTest.php @@ -23,7 +23,7 @@ final class ImportIconCommandTest extends KernelTestCase use InteractsWithConsole; private const ICON_DIR = __DIR__.'/../../Fixtures/icons'; - private const ICONS = ['uiw/dashboard.svg']; + private const ICONS = ['uiw/dashboard.svg', 'lucide/circle.svg']; /** * @before @@ -45,8 +45,8 @@ public function testCanImportIcon(): void $this->executeConsoleCommand('ux:icons:import uiw:dashboard') ->assertSuccessful() + ->assertOutputContains('Icon set: uiw icons (License: MIT)') ->assertOutputContains('Importing uiw:dashboard') - ->assertOutputContains("Imported uiw:dashboard (License: MIT). Render with: {{ ux_icon('uiw:dashboard') }}") ; $this->assertFileExists($expectedFile); @@ -60,13 +60,34 @@ public function testImportInvalidIconName(): void ; } - public function testImportNonExistentIcon(): void + public function testImportNonExistentIconSet(): void { $this->executeConsoleCommand('ux:icons:import something:invalid') ->assertStatusCode(1) - ->assertOutputContains('[ERROR] The icon "something:invalid" does not exist on iconify.design.') + ->assertOutputContains('[ERROR] Icon set "something" not found.') + ; + } + + public function testImportNonExistentIcon(): void + { + $this->executeConsoleCommand('ux:icons:import lucide:not-existing-icon') + ->assertStatusCode(1) + ->assertOutputContains('Not Found lucide:not-existing-icon') + ->assertOutputContains('[ERROR] Imported 0/1 icons.') + ; + + $this->assertFileDoesNotExist(self::ICON_DIR.'/not-existing-icon.svg'); + } + + public function testImportNonExistentIconWithExistentOne(): void + { + $this->executeConsoleCommand('ux:icons:import lucide:circle lucide:not-existing-icon') + ->assertStatusCode(0) + ->assertOutputContains('Imported lucide:circle') + ->assertOutputContains('Not Found lucide:not-existing-icon') + ->assertOutputContains('[WARNING] Imported 1/2 icons.') ; - $this->assertFileDoesNotExist(self::ICON_DIR.'/invalid.svg'); + $this->assertFileDoesNotExist(self::ICON_DIR.'/not-existing-icon.svg'); } } diff --git a/src/Icons/tests/Unit/IconifyTest.php b/src/Icons/tests/Unit/IconifyTest.php index 3fafce3abcc..c6edef0cf3a 100644 --- a/src/Icons/tests/Unit/IconifyTest.php +++ b/src/Icons/tests/Unit/IconifyTest.php @@ -238,6 +238,85 @@ public function testGetMetadata(): void $this->assertSame('Font Awesome Solid', $metadata['name']); } + /** + * @dataProvider provideChunkCases + */ + public function testChunk(int $maxQueryLength, string $prefix, array $names, array $chunks): void + { + $iconify = new Iconify( + new NullAdapter(), + 'https://example.com', + new MockHttpClient([]), + $maxQueryLength, + ); + + $this->assertSame($chunks, iterator_to_array($iconify->chunk($prefix, $names))); + } + + public static function provideChunkCases(): iterable + { + yield 'no icon should make no chunk' => [ + 10, + 'ppppp', + [], + [], + ]; + + yield 'one icon should make one chunk' => [ + 10, + 'ppppp', + ['aaaa1'], + [['aaaa1']], + ]; + + yield 'two icons that should make two chunck' => [ + 10, + 'ppppp', + ['aa1', 'aa2'], + [['aa1'], ['aa2']], + ]; + + yield 'three icons that should make two chunck' => [ + 15, + 'ppppp', + ['aaa1', 'aaa2', 'aaa3'], + [['aaa1', 'aaa2'], ['aaa3']], + ]; + + yield 'four icons that should make two chunck' => [ + 15, + 'ppppp', + ['aaaaaaaa1', 'a2', 'a3', 'a4'], + [['aaaaaaaa1'], ['a2', 'a3', 'a4']], + ]; + } + + public function testChunkThrowWithIconPrefixTooLong(): void + { + $iconify = new Iconify(new NullAdapter(), 'https://example.com', new MockHttpClient([])); + + $prefix = str_pad('p', 101, 'p'); + $name = 'icon'; + + $this->expectExceptionMessage(\sprintf('The icon prefix "%s" is too long.', $prefix)); + + // We need to iterate over the iterator to trigger the exception + $result = iterator_to_array($iconify->chunk($prefix, [$name])); + } + + public function testChunkThrowWithIconNameTooLong(): void + { + $iconify = new Iconify(new NullAdapter(), 'https://example.com', new MockHttpClient([])); + + $prefix = 'prefix'; + $name = str_pad('n', 101, 'n'); + + $this->expectExceptionMessage(\sprintf('The icon name "%s" is too long.', $name)); + + // We need to iterate over the iterator to trigger the exception + $result = iterator_to_array($iconify->chunk($prefix, [$name])); + } + private function createHttpClient(mixed $data, int $code = 200): MockHttpClient { $mockResponse = new JsonMockResponse($data, ['http_code' => $code]); From 6486933ca0682ca4d74ea3855ba1a11510901de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Wed, 6 Nov 2024 03:40:32 +0100 Subject: [PATCH 32/42] [TwigComponent] Improve ComponentFactory performances --- src/TwigComponent/src/ComponentFactory.php | 62 +++++++++++-------- .../TwigComponentExtension.php | 1 + .../Integration/ComponentFactoryTest.php | 2 +- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/TwigComponent/src/ComponentFactory.php b/src/TwigComponent/src/ComponentFactory.php index d797c399add..c191bc1bb4a 100644 --- a/src/TwigComponent/src/ComponentFactory.php +++ b/src/TwigComponent/src/ComponentFactory.php @@ -14,6 +14,7 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use Symfony\Contracts\Service\ResetInterface; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; use Symfony\UX\TwigComponent\Event\PostMountEvent; use Symfony\UX\TwigComponent\Event\PreMountEvent; @@ -23,8 +24,12 @@ * * @internal */ -final class ComponentFactory +final class ComponentFactory implements ResetInterface { + private static $mountMethods = []; + private static $preMountMethods = []; + private static $postMountMethods = []; + /** * @param array $config * @param array $classMap @@ -141,37 +146,40 @@ public function get(string $name): object private function mount(object $component, array &$data): void { - try { - $method = (new \ReflectionClass($component))->getMethod('mount'); - } catch (\ReflectionException) { - // no hydrate method - return; - } - if ($component instanceof AnonymousComponent) { $component->mount($data); return; } - $parameters = []; + if (null === (self::$mountMethods[$component::class] ?? null)) { + try { + $mountMethod = self::$mountMethods[$component::class] = (new \ReflectionClass($component))->getMethod('mount'); + } catch (\ReflectionException) { + self::$mountMethods[$component::class] = false; - foreach ($method->getParameters() as $refParameter) { - $name = $refParameter->getName(); + return; + } + } - if (\array_key_exists($name, $data)) { - $parameters[] = $data[$name]; + if (false === $mountMethod ??= self::$mountMethods[$component::class]) { + return; + } + $parameters = []; + foreach ($mountMethod->getParameters() as $refParameter) { + if (\array_key_exists($name = $refParameter->getName(), $data)) { + $parameters[] = $data[$name]; // remove the data element so it isn't used to set the property directly. unset($data[$name]); } elseif ($refParameter->isDefaultValueAvailable()) { $parameters[] = $refParameter->getDefaultValue(); } else { - throw new \LogicException(\sprintf('%s::mount() has a required $%s parameter. Make sure this is passed or make give a default value.', $component::class, $refParameter->getName())); + throw new \LogicException(\sprintf('%s::mount() has a required $%s parameter. Make sure to pass it or give it a default value.', $component::class, $name)); } } - $component->mount(...$parameters); + $mountMethod->invoke($component, ...$parameters); } private function preMount(object $component, array $data, ComponentMetadata $componentMetadata): array @@ -180,10 +188,9 @@ private function preMount(object $component, array $data, ComponentMetadata $com $this->eventDispatcher->dispatch($event); $data = $event->getData(); - foreach (AsTwigComponent::preMountMethods($component) as $method) { - $newData = $component->{$method->name}($data); - - if (null !== $newData) { + $methods = self::$preMountMethods[$component::class] ??= AsTwigComponent::preMountMethods($component::class); + foreach ($methods as $method) { + if (null !== $newData = $method->invoke($component, $data)) { $data = $newData; } } @@ -199,19 +206,17 @@ private function postMount(object $component, array $data, ComponentMetadata $co $event = new PostMountEvent($component, $data, $componentMetadata); $this->eventDispatcher->dispatch($event); $data = $event->getData(); - $extraMetadata = $event->getExtraMetadata(); - foreach (AsTwigComponent::postMountMethods($component) as $method) { - $newData = $component->{$method->name}($data); - - if (null !== $newData) { + $methods = self::$postMountMethods[$component::class] ??= AsTwigComponent::postMountMethods($component::class); + foreach ($methods as $method) { + if (null !== $newData = $method->invoke($component, $data)) { $data = $newData; } } return [ 'data' => $data, - 'extraMetadata' => $extraMetadata, + 'extraMetadata' => $event->getExtraMetadata(), ]; } @@ -248,4 +253,11 @@ private function throwUnknownComponentException(string $name): void throw new \InvalidArgumentException($message); } + + public function reset(): void + { + self::$mountMethods = []; + self::$preMountMethods = []; + self::$postMountMethods = []; + } } diff --git a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php index 0ee7230600a..19432f6305a 100644 --- a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php +++ b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php @@ -92,6 +92,7 @@ static function (ChildDefinition $definition, AsTwigComponent $attribute) { new Reference('event_dispatcher'), new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)), ]) + ->addTag('kernel.reset', ['method' => 'reset']) ; $container->register('ux.twig_component.component_stack', ComponentStack::class); diff --git a/src/TwigComponent/tests/Integration/ComponentFactoryTest.php b/src/TwigComponent/tests/Integration/ComponentFactoryTest.php index 72064f47669..bf5dd88675d 100644 --- a/src/TwigComponent/tests/Integration/ComponentFactoryTest.php +++ b/src/TwigComponent/tests/Integration/ComponentFactoryTest.php @@ -87,7 +87,7 @@ public function testMountCanHaveOptionalParameters(): void public function testExceptionThrownIfRequiredMountParameterIsMissingFromPassedData(): void { $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Symfony\UX\TwigComponent\Tests\Fixtures\Component\ComponentC::mount() has a required $propA parameter. Make sure this is passed or make give a default value.'); + $this->expectExceptionMessage('Symfony\UX\TwigComponent\Tests\Fixtures\Component\ComponentC::mount() has a required $propA parameter. Make sure to pass it or give it a default value.'); $this->createComponent('component_c'); } From cbacecc8a2c978993bf264f548bd9657ca7128ce Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Thu, 7 Nov 2024 20:06:43 +0100 Subject: [PATCH 33/42] [Map] Introduce `ux_map.google_maps.default_map_id` configuration --- src/Map/CHANGELOG.md | 5 +++++ src/Map/config/twig_component.php | 2 -- src/Map/src/Bridge/Google/CHANGELOG.md | 6 ++++++ .../src/Bridge/Google/src/GoogleOptions.php | 5 +++++ .../Google/src/Renderer/GoogleRenderer.php | 16 +++++++++++++++- .../src/Renderer/GoogleRendererFactory.php | 9 +++++++++ .../Bridge/Google/tests/GoogleRendererTest.php | 18 ++++++++++++++++++ src/Map/src/Renderer/AbstractRenderer.php | 14 ++++++++++++++ src/Map/src/UXMapBundle.php | 16 +++++++++++++++- 9 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/Map/CHANGELOG.md b/src/Map/CHANGELOG.md index 3883fe057d4..ef718fcb7ca 100644 --- a/src/Map/CHANGELOG.md +++ b/src/Map/CHANGELOG.md @@ -1,4 +1,9 @@ # CHANGELOG + +## 2.22 + +- Add method `Symfony\UX\Map\Renderer\AbstractRenderer::tapOptions()`, to allow Renderer to modify options before rendering a Map. +- Add `ux_map.google_maps.default_map_id` configuration to set the Google ``Map ID`` ## 2.20 diff --git a/src/Map/config/twig_component.php b/src/Map/config/twig_component.php index 096eec4aea8..0a3ad404ad5 100644 --- a/src/Map/config/twig_component.php +++ b/src/Map/config/twig_component.php @@ -12,8 +12,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Symfony\UX\Map\Twig\UXMapComponent; -use Symfony\UX\Map\Twig\UXMapComponentListener; -use Symfony\UX\TwigComponent\Event\PreCreateForRenderEvent; return static function (ContainerConfigurator $container): void { $container->services() diff --git a/src/Map/src/Bridge/Google/CHANGELOG.md b/src/Map/src/Bridge/Google/CHANGELOG.md index 46f7d49c2f0..48478b9806b 100644 --- a/src/Map/src/Bridge/Google/CHANGELOG.md +++ b/src/Map/src/Bridge/Google/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 2.22 + +- Add support for configuring a default Map ID +- Add argument `$defaultMapId` to `Symfony\UX\Map\Bridge\Google\Renderer\GoogleRendererFactory` constructor +- Add argument `$defaultMapId` to `Symfony\UX\Map\Bridge\Google\Renderer\GoogleRenderer` constructor + ## 2.20 ### BC Breaks diff --git a/src/Map/src/Bridge/Google/src/GoogleOptions.php b/src/Map/src/Bridge/Google/src/GoogleOptions.php index 8b26efcfba9..a241daa80e6 100644 --- a/src/Map/src/Bridge/Google/src/GoogleOptions.php +++ b/src/Map/src/Bridge/Google/src/GoogleOptions.php @@ -46,6 +46,11 @@ public function mapId(?string $mapId): self return $this; } + public function hasMapId(): bool + { + return null !== $this->mapId; + } + public function gestureHandling(GestureHandling $gestureHandling): self { $this->gestureHandling = $gestureHandling; diff --git a/src/Map/src/Bridge/Google/src/Renderer/GoogleRenderer.php b/src/Map/src/Bridge/Google/src/Renderer/GoogleRenderer.php index 808278abbf3..cb325ba0171 100644 --- a/src/Map/src/Bridge/Google/src/Renderer/GoogleRenderer.php +++ b/src/Map/src/Bridge/Google/src/Renderer/GoogleRenderer.php @@ -41,6 +41,7 @@ public function __construct( * @var array<'core'|'maps'|'places'|'geocoding'|'routes'|'marker'|'geometry'|'elevation'|'streetView'|'journeySharing'|'drawing'|'visualization'> */ private array $libraries = [], + private ?string $defaultMapId = null, ) { parent::__construct($stimulusHelper); } @@ -66,7 +67,20 @@ protected function getProviderOptions(): array protected function getDefaultMapOptions(): MapOptionsInterface { - return new GoogleOptions(); + return new GoogleOptions(mapId: $this->defaultMapId); + } + + protected function tapOptions(MapOptionsInterface $options): MapOptionsInterface + { + if (!$options instanceof GoogleOptions) { + throw new \InvalidArgumentException(\sprintf('The options must be an instance of "%s", got "%s" instead.', GoogleOptions::class, get_debug_type($options))); + } + + if (!$options->hasMapId()) { + $options->mapId($this->defaultMapId); + } + + return $options; } public function __toString(): string diff --git a/src/Map/src/Bridge/Google/src/Renderer/GoogleRendererFactory.php b/src/Map/src/Bridge/Google/src/Renderer/GoogleRendererFactory.php index a391f676152..e34956349ad 100644 --- a/src/Map/src/Bridge/Google/src/Renderer/GoogleRendererFactory.php +++ b/src/Map/src/Bridge/Google/src/Renderer/GoogleRendererFactory.php @@ -17,12 +17,20 @@ use Symfony\UX\Map\Renderer\Dsn; use Symfony\UX\Map\Renderer\RendererFactoryInterface; use Symfony\UX\Map\Renderer\RendererInterface; +use Symfony\UX\StimulusBundle\Helper\StimulusHelper; /** * @author Hugo Alliaume */ final class GoogleRendererFactory extends AbstractRendererFactory implements RendererFactoryInterface { + public function __construct( + StimulusHelper $stimulus, + private ?string $defaultMapId = null, + ) { + parent::__construct($stimulus); + } + public function create(Dsn $dsn): RendererInterface { if (!$this->supports($dsn)) { @@ -42,6 +50,7 @@ public function create(Dsn $dsn): RendererInterface url: $dsn->getOption('url'), version: $dsn->getOption('version', 'weekly'), libraries: ['maps', 'marker', ...$dsn->getOption('libraries', [])], + defaultMapId: $this->defaultMapId, ); } diff --git a/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php b/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php index e688d0c89f3..358eb2fa353 100644 --- a/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php +++ b/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php @@ -78,5 +78,23 @@ public function provideTestRenderMap(): iterable fullscreenControl: false, )), ]; + + yield 'with default map id' => [ + 'expected_renderer' => '
', + 'renderer' => new GoogleRenderer(new StimulusHelper(null), 'my_api_key', defaultMapId: 'DefaultMapId'), + 'map' => (clone $map), + ]; + yield 'with default map id, when passing options (except the "mapId")' => [ + 'expected_renderer' => '
', + 'renderer' => new GoogleRenderer(new StimulusHelper(null), 'my_api_key', defaultMapId: 'DefaultMapId'), + 'map' => (clone $map) + ->options(new GoogleOptions()), + ]; + yield 'with default map id overridden by option "mapId"' => [ + 'expected_renderer' => '
', + 'renderer' => new GoogleRenderer(new StimulusHelper(null), 'my_api_key', defaultMapId: 'DefaultMapId'), + 'map' => (clone $map) + ->options(new GoogleOptions(mapId: 'CustomMapId')), + ]; } } diff --git a/src/Map/src/Renderer/AbstractRenderer.php b/src/Map/src/Renderer/AbstractRenderer.php index aa229009fd9..4471f9be36a 100644 --- a/src/Map/src/Renderer/AbstractRenderer.php +++ b/src/Map/src/Renderer/AbstractRenderer.php @@ -31,6 +31,18 @@ abstract protected function getProviderOptions(): array; abstract protected function getDefaultMapOptions(): MapOptionsInterface; + /** + * @template T of MapOptionsInterface + * + * @param T $options + * + * @return T + */ + protected function tapOptions(MapOptionsInterface $options): MapOptionsInterface + { + return $options; + } + final public function renderMap(Map $map, array $attributes = []): string { if (!$map->hasOptions()) { @@ -39,6 +51,8 @@ final public function renderMap(Map $map, array $attributes = []): string $map->options($defaultMapOptions); } + $map->options($this->tapOptions($map->getOptions())); + $controllers = []; if ($attributes['data-controller'] ?? null) { $controllers[$attributes['data-controller']] = []; diff --git a/src/Map/src/UXMapBundle.php b/src/Map/src/UXMapBundle.php index 1392926131f..2f4bb35a837 100644 --- a/src/Map/src/UXMapBundle.php +++ b/src/Map/src/UXMapBundle.php @@ -44,6 +44,12 @@ public function configure(DefinitionConfigurator $definition): void $rootNode ->children() ->scalarNode('renderer')->defaultNull()->end() + ->arrayNode('google_maps') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('default_map_id')->defaultNull()->end() + ->end() + ->end() ->end() ; } @@ -75,9 +81,17 @@ public function loadExtension(array $config, ContainerConfigurator $container, C foreach (self::$bridges as $name => $bridge) { if (ContainerBuilder::willBeAvailable('symfony/ux-'.$name.'-map', $bridge['renderer_factory'], ['symfony/ux-map'])) { $container->services() - ->set('ux_map.renderer_factory.'.$name, $bridge['renderer_factory']) + ->set($rendererFactoryName = 'ux_map.renderer_factory.'.$name, $bridge['renderer_factory']) ->parent('ux_map.renderer_factory.abstract') ->tag('ux_map.renderer_factory'); + + if ('google' === $name) { + $container->services() + ->get($rendererFactoryName) + ->args([ + '$defaultMapId' => $config['google_maps']['default_map_id'], + ]); + } } } } From 18d7b6b79260dc9408b74c230737d17353f5206a Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sun, 10 Nov 2024 08:49:16 +0100 Subject: [PATCH 34/42] [Map][Google] Add documentation about ux_map.google_maps.default_map_id --- src/Map/doc/index.rst | 6 ++++++ src/Map/src/Bridge/Google/README.md | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Map/doc/index.rst b/src/Map/doc/index.rst index c6d49cfdc7d..6c22bc8a42f 100644 --- a/src/Map/doc/index.rst +++ b/src/Map/doc/index.rst @@ -34,6 +34,12 @@ Configuration is done in your ``config/packages/ux_map.yaml`` file: # config/packages/ux_map.yaml ux_map: renderer: '%env(resolve:default::UX_MAP_DSN)%' + + # Google Maps specific configuration + google_maps: + # Configure the default Map Id (https://developers.google.com/maps/documentation/get-map-id), + # without to manually configure it in each map instance (through "new GoogleOptions(mapId: 'your_map_id')"). + default_map_id: null The ``UX_MAP_DSN`` environment variable configure which renderer to use. diff --git a/src/Map/src/Bridge/Google/README.md b/src/Map/src/Bridge/Google/README.md index d46bd700833..59a55a06f24 100644 --- a/src/Map/src/Bridge/Google/README.md +++ b/src/Map/src/Bridge/Google/README.md @@ -46,9 +46,12 @@ $map = (new Map()) ->center(new Point(48.8566, 2.3522)) ->zoom(6); -// To configure controls options, and some other options: +// To configure control options and other map options: $googleOptions = (new GoogleOptions()) - ->mapId('YOUR_MAP_ID') + // You can skip this option if you configure "ux_map.google_maps.default_map_id" + // in your "config/packages/ux_map.yaml". + ->mapId('YOUR_MAP_ID') + ->gestureHandling(GestureHandling::GREEDY) ->backgroundColor('#f00') ->doubleClickZoom(true) From a432df844007d7e9516710b1ad7d50d6b3b8596a Mon Sep 17 00:00:00 2001 From: Tac Tacelosky Date: Sun, 10 Nov 2024 05:53:45 -0500 Subject: [PATCH 35/42] add position and missing closing parenthesis so that it works when blindly cutting and pasting. --- src/Map/doc/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Map/doc/index.rst b/src/Map/doc/index.rst index c6d49cfdc7d..2f3268e9898 100644 --- a/src/Map/doc/index.rst +++ b/src/Map/doc/index.rst @@ -116,7 +116,7 @@ You can add markers to a map using the ``addMarker()`` method:: // You can also pass arbitrary data via the `extra` option in both the marker // and the infoWindow; you can later use this data in your custom Stimulus controllers ->addMarker(new Marker( - // ... + position: new Point(45.7740, 4.8351), extra: [ 'icon_mask_url' => 'https://maps.gstatic.com/mapfiles/place_api/icons/v2/tree_pinlet.svg', ], @@ -127,7 +127,7 @@ You can add markers to a map using the ``addMarker()`` method:: 'includes_link' => true, ], ), - ) + )) ; Add Polygons From c67028fc530adcb94918c5a5f310c39e94383c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sun, 10 Nov 2024 04:43:57 +0100 Subject: [PATCH 36/42] [TwigComponent] Store mount methods in compiler pass --- .../Integration/LiveComponentHydratorTest.php | 5 +- .../src/Attribute/AsTwigComponent.php | 40 ---------- .../src/Command/TwigComponentDebugCommand.php | 18 ++--- src/TwigComponent/src/ComponentFactory.php | 42 ++++------ src/TwigComponent/src/ComponentMetadata.php | 30 ++++++++ .../Compiler/TwigComponentPass.php | 35 ++++++++- .../AcmeComponent/AcmeRootComponent.php | 1 - .../AcmeSubDir/AcmeOtherComponent.php | 1 - .../tests/Fixtures/Component/Conflict.php | 2 +- .../SubDirectory/ComponentInSubDirectory.php | 1 - .../Integration/ComponentExtensionTest.php | 12 ++- .../Unit/Attribute/AsTwigComponentTest.php | 77 ------------------- .../tests/Unit/ComponentFactoryTest.php | 7 +- 13 files changed, 105 insertions(+), 166 deletions(-) delete mode 100644 src/TwigComponent/tests/Unit/Attribute/AsTwigComponentTest.php diff --git a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php index 511a5580f72..66ea8cd24d6 100644 --- a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php +++ b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php @@ -1872,7 +1872,10 @@ public function getTest(LiveComponentMetadataFactory $metadataFactory): Hydratio return new HydrationTestCase( $this->component, new LiveComponentMetadata( - new ComponentMetadata(['key' => '__testing']), + new ComponentMetadata([ + 'key' => '__testing', + 'mount' => $reflectionClass->hasMethod('mount') ? ['mount'] : [], + ]), $metadataFactory->createPropMetadatas($reflectionClass), ), $this->inputProps, diff --git a/src/TwigComponent/src/Attribute/AsTwigComponent.php b/src/TwigComponent/src/Attribute/AsTwigComponent.php index d58e5647ae8..829fd5bfbdb 100644 --- a/src/TwigComponent/src/Attribute/AsTwigComponent.php +++ b/src/TwigComponent/src/Attribute/AsTwigComponent.php @@ -75,46 +75,6 @@ public function serviceConfig(): array ]; } - /** - * @param object|class-string $component - * - * @internal - */ - public static function mountMethod(object|string $component): ?\ReflectionMethod - { - foreach ((new \ReflectionClass($component))->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { - if ('mount' === $method->getName()) { - return $method; - } - } - - return null; - } - - /** - * @param object|class-string $component - * - * @return \ReflectionMethod[] - * - * @internal - */ - public static function postMountMethods(object|string $component): array - { - return self::attributeMethodsByPriorityFor($component, PostMount::class); - } - - /** - * @param object|class-string $component - * - * @return \ReflectionMethod[] - * - * @internal - */ - public static function preMountMethods(object|string $component): array - { - return self::attributeMethodsByPriorityFor($component, PreMount::class); - } - /** * @param object|class-string $component * @param class-string $attributeClass diff --git a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php index 843138026c6..f883f59ef96 100644 --- a/src/TwigComponent/src/Command/TwigComponentDebugCommand.php +++ b/src/TwigComponent/src/Command/TwigComponentDebugCommand.php @@ -21,7 +21,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Finder\Finder; -use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate; use Symfony\UX\TwigComponent\ComponentFactory; use Symfony\UX\TwigComponent\ComponentMetadata; @@ -214,7 +213,7 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void ]); // Anonymous Component - if (null === $metadata->get('class')) { + if ($metadata->isAnonymous()) { $table->addRows([ ['Type', 'Anonymous'], new TableSeparator(), @@ -229,7 +228,7 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void ['Type', $metadata->get('live') ? 'Live' : ''], new TableSeparator(), // ['Attributes Var', $metadata->get('attributes_var')], - ['Public Props', $metadata->get('expose_public_props') ? 'Yes' : 'No'], + ['Public Props', $metadata->isPublicPropsExposed() ? 'Yes' : 'No'], ['Properties', implode("\n", $this->getComponentProperties($metadata))], ]); @@ -242,14 +241,15 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void return \sprintf('%s(%s)', $m->getName(), implode(', ', $params)); }; $hooks = []; - if ($method = AsTwigComponent::mountMethod($metadata->getClass())) { - $hooks[] = ['Mount', $logMethod($method)]; + $reflector = new \ReflectionClass($metadata->getClass()); + foreach ($metadata->getPreMounts() as $method) { + $hooks[] = ['PreMount', $logMethod($reflector->getMethod($method))]; } - foreach (AsTwigComponent::preMountMethods($metadata->getClass()) as $method) { - $hooks[] = ['PreMount', $logMethod($method)]; + foreach ($metadata->getMounts() as $method) { + $hooks[] = ['Mount', $logMethod($reflector->getMethod($method))]; } - foreach (AsTwigComponent::postMountMethods($metadata->getClass()) as $method) { - $hooks[] = ['PostMount', $logMethod($method)]; + foreach ($metadata->getPostMounts() as $method) { + $hooks[] = ['PostMount', $logMethod($reflector->getMethod($method))]; } if ($hooks) { $table->addRows([ diff --git a/src/TwigComponent/src/ComponentFactory.php b/src/TwigComponent/src/ComponentFactory.php index c191bc1bb4a..8699fb10a32 100644 --- a/src/TwigComponent/src/ComponentFactory.php +++ b/src/TwigComponent/src/ComponentFactory.php @@ -15,7 +15,6 @@ use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Contracts\Service\ResetInterface; -use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; use Symfony\UX\TwigComponent\Event\PostMountEvent; use Symfony\UX\TwigComponent\Event\PreMountEvent; @@ -26,13 +25,12 @@ */ final class ComponentFactory implements ResetInterface { - private static $mountMethods = []; - private static $preMountMethods = []; - private static $postMountMethods = []; + private static array $mountMethods = []; /** * @param array $config * @param array $classMap + * @param array $classMounts */ public function __construct( private ComponentTemplateFinderInterface $componentTemplateFinder, @@ -92,7 +90,7 @@ public function mountFromObject(object $component, array $data, ComponentMetadat $originalData = $data; $data = $this->preMount($component, $data, $componentMetadata); - $this->mount($component, $data); + $this->mount($component, $data, $componentMetadata); // set data that wasn't set in mount on the component directly foreach ($data as $property => $value) { @@ -144,7 +142,7 @@ public function get(string $name): object return $this->components->get($metadata->getName()); } - private function mount(object $component, array &$data): void + private function mount(object $component, array &$data, ComponentMetadata $componentMetadata): void { if ($component instanceof AnonymousComponent) { $component->mount($data); @@ -152,22 +150,14 @@ private function mount(object $component, array &$data): void return; } - if (null === (self::$mountMethods[$component::class] ?? null)) { - try { - $mountMethod = self::$mountMethods[$component::class] = (new \ReflectionClass($component))->getMethod('mount'); - } catch (\ReflectionException) { - self::$mountMethods[$component::class] = false; - - return; - } - } - - if (false === $mountMethod ??= self::$mountMethods[$component::class]) { + if (!$componentMetadata->getMounts()) { return; } + $mount = self::$mountMethods[$component::class] ??= (new \ReflectionClass($component))->getMethod('mount'); + $parameters = []; - foreach ($mountMethod->getParameters() as $refParameter) { + foreach ($mount->getParameters() as $refParameter) { if (\array_key_exists($name = $refParameter->getName(), $data)) { $parameters[] = $data[$name]; // remove the data element so it isn't used to set the property directly. @@ -175,11 +165,11 @@ private function mount(object $component, array &$data): void } elseif ($refParameter->isDefaultValueAvailable()) { $parameters[] = $refParameter->getDefaultValue(); } else { - throw new \LogicException(\sprintf('%s::mount() has a required $%s parameter. Make sure to pass it or give it a default value.', $component::class, $name)); + throw new \LogicException(\sprintf('%s has a required $%s parameter. Make sure to pass it or give it a default value.', $component::class.'::mount()', $name)); } } - $mountMethod->invoke($component, ...$parameters); + $mount->invoke($component, ...$parameters); } private function preMount(object $component, array $data, ComponentMetadata $componentMetadata): array @@ -188,9 +178,8 @@ private function preMount(object $component, array $data, ComponentMetadata $com $this->eventDispatcher->dispatch($event); $data = $event->getData(); - $methods = self::$preMountMethods[$component::class] ??= AsTwigComponent::preMountMethods($component::class); - foreach ($methods as $method) { - if (null !== $newData = $method->invoke($component, $data)) { + foreach ($componentMetadata->getPreMounts() as $preMount) { + if (null !== $newData = $component->$preMount($data)) { $data = $newData; } } @@ -207,9 +196,8 @@ private function postMount(object $component, array $data, ComponentMetadata $co $this->eventDispatcher->dispatch($event); $data = $event->getData(); - $methods = self::$postMountMethods[$component::class] ??= AsTwigComponent::postMountMethods($component::class); - foreach ($methods as $method) { - if (null !== $newData = $method->invoke($component, $data)) { + foreach ($componentMetadata->getPostMounts() as $postMount) { + if (null !== $newData = $component->$postMount($data)) { $data = $newData; } } @@ -257,7 +245,5 @@ private function throwUnknownComponentException(string $name): void public function reset(): void { self::$mountMethods = []; - self::$preMountMethods = []; - self::$postMountMethods = []; } } diff --git a/src/TwigComponent/src/ComponentMetadata.php b/src/TwigComponent/src/ComponentMetadata.php index b71e349161c..4eb30327eca 100644 --- a/src/TwigComponent/src/ComponentMetadata.php +++ b/src/TwigComponent/src/ComponentMetadata.php @@ -67,6 +67,36 @@ public function getAttributesVar(): string return $this->get('attributes_var', 'attributes'); } + /** + * @return list + * + * @internal + */ + public function getPreMounts(): array + { + return $this->get('pre_mount', []); + } + + /** + * @return list + * + * @internal + */ + public function getMounts(): array + { + return $this->get('mount', []); + } + + /** + * @return list + * + * @internal + */ + public function getPostMounts(): array + { + return $this->get('post_mount', []); + } + public function get(string $key, mixed $default = null): mixed { return $this->config[$key] ?? $default; diff --git a/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php b/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php index faf86afe925..b39ae4535dc 100644 --- a/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php +++ b/src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php @@ -16,6 +16,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\UX\TwigComponent\Attribute\PostMount; +use Symfony\UX\TwigComponent\Attribute\PreMount; /** * @author Kevin Bond @@ -68,7 +70,7 @@ public function process(ContainerBuilder $container): void $tag['service_id'] = $id; $tag['class'] = $definition->getClass(); $tag['template'] = $tag['template'] ?? $this->calculateTemplate($tag['key'], $defaults); - $componentConfig[$tag['key']] = $tag; + $componentConfig[$tag['key']] = [...$tag, ...$this->getMountMethods($tag['class'])]; $componentReferences[$tag['key']] = new Reference($id); $componentNames[] = $tag['key']; $componentClassMap[$tag['class']] = $tag['key']; @@ -109,4 +111,35 @@ private function calculateTemplate(string $componentName, ?array $defaults): str return \sprintf('%s/%s.html.twig', rtrim($directory, '/'), str_replace(':', '/', $componentName)); } + + /** + * @param class-string $component + * + * @return array{preMount: string[], mount: string[], postMount: string[]} + */ + private function getMountMethods(string $component): array + { + $preMount = $mount = $postMount = []; + foreach ((new \ReflectionClass($component))->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { + foreach ($method->getAttributes(PreMount::class) as $attribute) { + $preMount[$method->getName()] = $attribute->newInstance()->priority; + } + foreach ($method->getAttributes(PostMount::class) as $attribute) { + $postMount[$method->getName()] = $attribute->newInstance()->priority; + } + if ('mount' === $method->getName()) { + $mount['mount'] = 0; + } + } + + arsort($preMount, \SORT_NUMERIC); + arsort($mount, \SORT_NUMERIC); + arsort($postMount, \SORT_NUMERIC); + + return [ + 'pre_mount' => array_keys($preMount), + 'mount' => array_keys($mount), + 'post_mount' => array_keys($postMount), + ]; + } } diff --git a/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeRootComponent.php b/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeRootComponent.php index 47fba424103..5783818d3c6 100644 --- a/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeRootComponent.php +++ b/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeRootComponent.php @@ -7,5 +7,4 @@ #[AsTwigComponent] class AcmeRootComponent { - } diff --git a/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeSubDir/AcmeOtherComponent.php b/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeSubDir/AcmeOtherComponent.php index d42ad45b77c..fa31f3eae84 100644 --- a/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeSubDir/AcmeOtherComponent.php +++ b/src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeSubDir/AcmeOtherComponent.php @@ -7,5 +7,4 @@ #[AsTwigComponent] class AcmeOtherComponent { - } diff --git a/src/TwigComponent/tests/Fixtures/Component/Conflict.php b/src/TwigComponent/tests/Fixtures/Component/Conflict.php index 0ffd16a80ee..c3b7960b175 100644 --- a/src/TwigComponent/tests/Fixtures/Component/Conflict.php +++ b/src/TwigComponent/tests/Fixtures/Component/Conflict.php @@ -8,4 +8,4 @@ class Conflict { public string $name; -} \ No newline at end of file +} diff --git a/src/TwigComponent/tests/Fixtures/Component/SubDirectory/ComponentInSubDirectory.php b/src/TwigComponent/tests/Fixtures/Component/SubDirectory/ComponentInSubDirectory.php index 723eafbc1a3..a7a53df45fe 100644 --- a/src/TwigComponent/tests/Fixtures/Component/SubDirectory/ComponentInSubDirectory.php +++ b/src/TwigComponent/tests/Fixtures/Component/SubDirectory/ComponentInSubDirectory.php @@ -7,5 +7,4 @@ #[AsTwigComponent] class ComponentInSubDirectory { - } diff --git a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php index 8b2b0e0987a..4f113262f88 100644 --- a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php +++ b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php @@ -283,7 +283,8 @@ public function testRenderingComponentWithNestedAttributes(): void { $output = $this->renderComponent('NestedAttributes'); - $this->assertSame(<<assertSame( + <<
@@ -302,7 +303,8 @@ public function testRenderingComponentWithNestedAttributes(): void 'title:span:class' => 'baz', ]); - $this->assertSame(<<assertSame( + <<
@@ -324,7 +326,8 @@ public function testRenderingHtmlSyntaxComponentWithNestedAttributes(): void ->render() ; - $this->assertSame(<<assertSame( + <<
@@ -343,7 +346,8 @@ public function testRenderingHtmlSyntaxComponentWithNestedAttributes(): void ->render() ; - $this->assertSame(<<assertSame( + <<
diff --git a/src/TwigComponent/tests/Unit/Attribute/AsTwigComponentTest.php b/src/TwigComponent/tests/Unit/Attribute/AsTwigComponentTest.php deleted file mode 100644 index 1606792ca99..00000000000 --- a/src/TwigComponent/tests/Unit/Attribute/AsTwigComponentTest.php +++ /dev/null @@ -1,77 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\TwigComponent\Tests\Unit; - -use PHPUnit\Framework\TestCase; -use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; -use Symfony\UX\TwigComponent\Attribute\PostMount; -use Symfony\UX\TwigComponent\Attribute\PreMount; - -/** - * @author Kevin Bond - */ -final class AsTwigComponentTest extends TestCase -{ - public function testPreMountHooksAreOrderedByPriority(): void - { - $hooks = AsTwigComponent::preMountMethods( - new class { - #[PreMount(priority: -10)] - public function hook1() - { - } - - #[PreMount(priority: 10)] - public function hook2() - { - } - - #[PreMount] - public function hook3() - { - } - } - ); - - $this->assertCount(3, $hooks); - $this->assertSame('hook2', $hooks[0]->name); - $this->assertSame('hook3', $hooks[1]->name); - $this->assertSame('hook1', $hooks[2]->name); - } - - public function testPostMountHooksAreOrderedByPriority(): void - { - $hooks = AsTwigComponent::postMountMethods( - new class { - #[PostMount(priority: -10)] - public function hook1() - { - } - - #[PostMount(priority: 10)] - public function hook2() - { - } - - #[PostMount] - public function hook3() - { - } - } - ); - - $this->assertCount(3, $hooks); - $this->assertSame('hook2', $hooks[0]->name); - $this->assertSame('hook3', $hooks[1]->name); - $this->assertSame('hook1', $hooks[2]->name); - } -} diff --git a/src/TwigComponent/tests/Unit/ComponentFactoryTest.php b/src/TwigComponent/tests/Unit/ComponentFactoryTest.php index fd1fd337c89..ccbf85f5cbc 100644 --- a/src/TwigComponent/tests/Unit/ComponentFactoryTest.php +++ b/src/TwigComponent/tests/Unit/ComponentFactoryTest.php @@ -31,7 +31,8 @@ public function testMetadataForConfig(): void $this->createMock(PropertyAccessorInterface::class), $this->createMock(EventDispatcherInterface::class), ['foo' => ['key' => 'foo', 'template' => 'bar.html.twig']], - [] + [], + [], ); $metadata = $factory->metadataFor('foo'); @@ -52,6 +53,7 @@ public function testMetadataForResolveAlias(): void 'foo' => ['key' => 'foo', 'template' => 'foo.html.twig'], ], ['Foo\\Bar' => 'bar'], + [], ); $metadata = $factory->metadataFor('Foo\\Bar'); @@ -74,7 +76,8 @@ public function testMetadataForReuseAnonymousConfig(): void $this->createMock(PropertyAccessorInterface::class), $this->createMock(EventDispatcherInterface::class), [], - [] + [], + [], ); $metadata = $factory->metadataFor('foo'); From 33bd17d45184138ed5e0a480338c624e45ee8bfc Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Wed, 13 Nov 2024 14:30:17 +0100 Subject: [PATCH 37/42] Remove duplicate question mark ? in DSN string --- src/Map/src/Bridge/Google/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Map/src/Bridge/Google/README.md b/src/Map/src/Bridge/Google/README.md index 59a55a06f24..707907cf568 100644 --- a/src/Map/src/Bridge/Google/README.md +++ b/src/Map/src/Bridge/Google/README.md @@ -10,7 +10,7 @@ UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default # With options UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default?version=weekly UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default?language=fr®ion=FR -UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default??libraries[]=geometry&libraries[]=places +UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default?libraries[]=geometry&libraries[]=places ``` Available options: From 2aa04d83568dfce39556133109cde6e3ca511861 Mon Sep 17 00:00:00 2001 From: Romain Monteil Date: Thu, 14 Nov 2024 12:16:33 +0100 Subject: [PATCH 38/42] [Map] Fix Twig Component example --- src/Map/doc/index.rst | 46 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/Map/doc/index.rst b/src/Map/doc/index.rst index 6c22bc8a42f..89bd6813552 100644 --- a/src/Map/doc/index.rst +++ b/src/Map/doc/index.rst @@ -30,11 +30,11 @@ Configuration Configuration is done in your ``config/packages/ux_map.yaml`` file: .. code-block:: yaml - + # config/packages/ux_map.yaml ux_map: renderer: '%env(resolve:default::UX_MAP_DSN)%' - + # Google Maps specific configuration google_maps: # Configure the default Map Id (https://developers.google.com/maps/documentation/get-map-id), @@ -47,8 +47,8 @@ Map renderers ~~~~~~~~~~~~~ The Symfony UX Map bundle supports multiple renderers. A map renderer is a -service that provides the code and graphic assets required to render and -interact with a map in the browser. +service that provides the code and graphic assets required to render and +interact with a map in the browser. Available renderers ~~~~~~~~~~~~~~~~~~~ @@ -75,7 +75,7 @@ Create a map A map is created by calling ``new Map()``. You can configure the center, zoom, and add markers. Start by creating a new map instance:: - + use Symfony\UX\Map\Map; // Create a new map instance @@ -88,12 +88,12 @@ You can set the center and zoom of the map using the ``center()`` and ``zoom()`` use Symfony\UX\Map\Map; use Symfony\UX\Map\Point; - + $myMap // Explicitly set the center and zoom ->center(new Point(46.903354, 1.888334)) ->zoom(6) - + // Or automatically fit the bounds to the markers ->fitBoundsToMarkers() ; @@ -105,13 +105,13 @@ You can add markers to a map using the ``addMarker()`` method:: $myMap ->addMarker(new Marker( - position: new Point(48.8566, 2.3522), + position: new Point(48.8566, 2.3522), title: 'Paris' )) // With an info window associated to the marker: ->addMarker(new Marker( - position: new Point(45.7640, 4.8357), + position: new Point(45.7640, 4.8357), title: 'Lyon', infoWindow: new InfoWindow( headerContent: 'Lyon', @@ -174,7 +174,7 @@ You can add custom HTML attributes too: Twig Function ``ux_map()`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``ux_map()`` Twig function allows you to create and render a map in your Twig +The ``ux_map()`` Twig function allows you to create and render a map in your Twig templates. The function accepts the same arguments as the ``Map`` class: .. code-block:: html+twig @@ -216,10 +216,8 @@ Alternatively, you can use the ```` component. "infoWindow": {"content": "Welcome to New York"} } ]' - attributes='{ - "class": "foo", - "style": "height: 800px; width: 100%; border: 4px solid red; margin-block: 10vh;" - }' + class="foo" + style="height: 800px; width: 100%; border: 4px solid red; margin-block: 10vh;" /> The ```` component requires the `Twig Component`_ package. @@ -236,9 +234,9 @@ Symfony UX Map allows you to extend its default behavior using a custom Stimulus .. code-block:: javascript // assets/controllers/mymap_controller.js - + import { Controller } from '@hotwired/stimulus'; - + export default class extends Controller { connect() { this.element.addEventListener('ux:map:pre-connect', this._onPreConnect); @@ -248,7 +246,7 @@ Symfony UX Map allows you to extend its default behavior using a custom Stimulus this.element.addEventListener('ux:map:info-window:before-create', this._onInfoWindowBeforeCreate); this.element.addEventListener('ux:map:info-window:after-create', this._onInfoWindowAfterCreate); } - + disconnect() { // You should always remove listeners when the controller is disconnected to avoid side effects this.element.removeEventListener('ux:map:pre-connect', this._onPreConnect); @@ -258,13 +256,13 @@ Symfony UX Map allows you to extend its default behavior using a custom Stimulus this.element.removeEventListener('ux:map:info-window:before-create', this._onInfoWindowBeforeCreate); this.element.removeEventListener('ux:map:info-window:after-create', this._onInfoWindowAfterCreate); } - + _onPreConnect(event) { // The map is not created yet // You can use this event to configure the map before it is created console.log(event.detail.options); } - + _onConnect(event) { // The map, markers and infoWindows are created // The instances depend on the renderer you are using @@ -272,19 +270,19 @@ Symfony UX Map allows you to extend its default behavior using a custom Stimulus console.log(event.detail.markers); console.log(event.detail.infoWindows); } - + _onMarkerBeforeCreate(event) { // The marker is not created yet // You can use this event to configure the marker before it is created console.log(event.detail.definition); } - + _onMarkerAfterCreate(event) { // The marker is created // The instance depends on the renderer you are using console.log(event.detail.marker); } - + _onInfoWindowBeforeCreate(event) { // The infoWindow is not created yet // You can use this event to configure the infoWindow before it is created @@ -292,7 +290,7 @@ Symfony UX Map allows you to extend its default behavior using a custom Stimulus // The associated marker instance is also available console.log(event.detail.marker); } - + _onInfoWindowAfterCreate(event) { // The infoWindow is created // The instance depends on the renderer you are using @@ -306,7 +304,7 @@ Symfony UX Map allows you to extend its default behavior using a custom Stimulus Then, you can use this controller in your template: .. code-block:: twig - + {{ ux_map(my_map, { 'data-controller': 'mymap', style: 'height: 300px' }) }} .. tip:: From 75a2997e4222e846ede2b2b5d5c6c26d5479263b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Mon, 11 Nov 2024 02:01:41 +0100 Subject: [PATCH 39/42] [Twig] Cache template class resolution --- .../Integration/LiveComponentHydratorTest.php | 1 + src/TwigComponent/src/ComponentFactory.php | 55 ++++++++----------- src/TwigComponent/src/ComponentRenderer.php | 18 ++++-- .../TwigComponentExtension.php | 1 + 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php index 66ea8cd24d6..004a6dff6a1 100644 --- a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php +++ b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php @@ -1875,6 +1875,7 @@ public function getTest(LiveComponentMetadataFactory $metadataFactory): Hydratio new ComponentMetadata([ 'key' => '__testing', 'mount' => $reflectionClass->hasMethod('mount') ? ['mount'] : [], + 'service_id' => '__testing_id', ]), $metadataFactory->createPropMetadatas($reflectionClass), ), diff --git a/src/TwigComponent/src/ComponentFactory.php b/src/TwigComponent/src/ComponentFactory.php index 8699fb10a32..9e2d618bd3f 100644 --- a/src/TwigComponent/src/ComponentFactory.php +++ b/src/TwigComponent/src/ComponentFactory.php @@ -25,12 +25,11 @@ */ final class ComponentFactory implements ResetInterface { - private static array $mountMethods = []; + private array $mountMethods = []; /** * @param array $config * @param array $classMap - * @param array $classMounts */ public function __construct( private ComponentTemplateFinderInterface $componentTemplateFinder, @@ -38,7 +37,7 @@ public function __construct( private PropertyAccessorInterface $propertyAccessor, private EventDispatcherInterface $eventDispatcher, private array $config, - private array $classMap, + private readonly array $classMap, ) { } @@ -88,29 +87,29 @@ public function create(string $name, array $data = []): MountedComponent public function mountFromObject(object $component, array $data, ComponentMetadata $componentMetadata): MountedComponent { $originalData = $data; - $data = $this->preMount($component, $data, $componentMetadata); + $event = $this->preMount($component, $data, $componentMetadata); + $data = $event->getData(); $this->mount($component, $data, $componentMetadata); - // set data that wasn't set in mount on the component directly - foreach ($data as $property => $value) { - if ($this->propertyAccessor->isWritable($component, $property)) { - $this->propertyAccessor->setValue($component, $property, $value); - - unset($data[$property]); + if (!$componentMetadata->isAnonymous()) { + // set data that wasn't set in mount on the component directly + foreach ($data as $property => $value) { + if ($this->propertyAccessor->isWritable($component, $property)) { + $this->propertyAccessor->setValue($component, $property, $value); + unset($data[$property]); + } } } $postMount = $this->postMount($component, $data, $componentMetadata); - $data = $postMount['data']; - $extraMetadata = $postMount['extraMetadata']; + $data = $postMount->getData(); // create attributes from "attributes" key if exists $attributesVar = $componentMetadata->getAttributesVar(); $attributes = $data[$attributesVar] ?? []; unset($data[$attributesVar]); - // ensure remaining data is scalar foreach ($data as $key => $value) { if ($value instanceof \Stringable) { $data[$key] = (string) $value; @@ -120,9 +119,9 @@ public function mountFromObject(object $component, array $data, ComponentMetadat return new MountedComponent( $componentMetadata->getName(), $component, - new ComponentAttributes(array_merge($attributes, $data)), + new ComponentAttributes([...$attributes, ...$data]), $originalData, - $extraMetadata, + $postMount->getExtraMetadata(), ); } @@ -154,7 +153,7 @@ private function mount(object $component, array &$data, ComponentMetadata $compo return; } - $mount = self::$mountMethods[$component::class] ??= (new \ReflectionClass($component))->getMethod('mount'); + $mount = $this->mountMethods[$component::class] ??= (new \ReflectionClass($component))->getMethod('mount'); $parameters = []; foreach ($mount->getParameters() as $refParameter) { @@ -172,40 +171,34 @@ private function mount(object $component, array &$data, ComponentMetadata $compo $mount->invoke($component, ...$parameters); } - private function preMount(object $component, array $data, ComponentMetadata $componentMetadata): array + private function preMount(object $component, array $data, ComponentMetadata $componentMetadata): PreMountEvent { $event = new PreMountEvent($component, $data, $componentMetadata); $this->eventDispatcher->dispatch($event); - $data = $event->getData(); + $data = $event->getData(); foreach ($componentMetadata->getPreMounts() as $preMount) { if (null !== $newData = $component->$preMount($data)) { - $data = $newData; + $event->setData($data = $newData); } } - return $data; + return $event; } - /** - * @return array{data: array, extraMetadata: array} - */ - private function postMount(object $component, array $data, ComponentMetadata $componentMetadata): array + private function postMount(object $component, array $data, ComponentMetadata $componentMetadata): PostMountEvent { $event = new PostMountEvent($component, $data, $componentMetadata); $this->eventDispatcher->dispatch($event); - $data = $event->getData(); + $data = $event->getData(); foreach ($componentMetadata->getPostMounts() as $postMount) { if (null !== $newData = $component->$postMount($data)) { - $data = $newData; + $event->setData($data = $newData); } } - return [ - 'data' => $data, - 'extraMetadata' => $event->getExtraMetadata(), - ]; + return $event; } /** @@ -244,6 +237,6 @@ private function throwUnknownComponentException(string $name): void public function reset(): void { - self::$mountMethods = []; + $this->mountMethods = []; } } diff --git a/src/TwigComponent/src/ComponentRenderer.php b/src/TwigComponent/src/ComponentRenderer.php index fb6a01ffda6..2595d646bbd 100644 --- a/src/TwigComponent/src/ComponentRenderer.php +++ b/src/TwigComponent/src/ComponentRenderer.php @@ -12,6 +12,7 @@ namespace Symfony\UX\TwigComponent; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Service\ResetInterface; use Symfony\UX\TwigComponent\Event\PostRenderEvent; use Symfony\UX\TwigComponent\Event\PreCreateForRenderEvent; use Symfony\UX\TwigComponent\Event\PreRenderEvent; @@ -22,8 +23,10 @@ * * @internal */ -final class ComponentRenderer implements ComponentRendererInterface +final class ComponentRenderer implements ComponentRendererInterface, ResetInterface { + private array $templateClasses = []; + public function __construct( private Environment $twig, private EventDispatcherInterface $dispatcher, @@ -62,15 +65,15 @@ public function render(MountedComponent $mounted): string $variables = $event->getVariables(); // see ComponentNode. When rendering an individual embedded component, // *not* through its parent, we need to set the parent template. - if ($event->getTemplateIndex()) { + if ($templateIndex = $event->getTemplateIndex()) { $variables['__parent__'] = $event->getParentTemplateForEmbedded(); } try { return $this->twig->loadTemplate( - $this->twig->getTemplateClass($event->getTemplate()), - $event->getTemplate(), - $event->getTemplateIndex(), + $this->templateClasses[$template = $event->getTemplate()] ??= $this->twig->getTemplateClass($template), + $template, + $templateIndex, )->render($variables); } finally { $mounted = $this->componentStack->pop(); @@ -137,4 +140,9 @@ private function preRender(MountedComponent $mounted, array $context = []): PreR return $event; } + + public function reset(): void + { + $this->templateClasses = []; + } } diff --git a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php index 19432f6305a..ebe2bb1753b 100644 --- a/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php +++ b/src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php @@ -113,6 +113,7 @@ static function (ChildDefinition $definition, AsTwigComponent $attribute) { new Reference('ux.twig_component.component_properties'), new Reference('ux.twig_component.component_stack'), ]) + ->addTag('kernel.reset', ['method' => 'reset']) ; $container->register('ux.twig_component.twig.component_extension', ComponentExtension::class) From a16d51d3054d1e60b5ebfd26380ecd394d83cc2f Mon Sep 17 00:00:00 2001 From: Matthieu Lempereur Date: Fri, 15 Nov 2024 20:31:49 +0100 Subject: [PATCH 40/42] [Svelte][Docs] Fix a broken link --- src/Svelte/doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Svelte/doc/index.rst b/src/Svelte/doc/index.rst index 4b25915626e..5daebc9a8bf 100644 --- a/src/Svelte/doc/index.rst +++ b/src/Svelte/doc/index.rst @@ -121,7 +121,7 @@ AssetMapper requires some extra steps. #. Compile your ``.svelte`` files to pure JavaScript files. This can be done by using the ``svelte/compiler`` library, but is a bit of a non-standard process. - For an example, see https://github.com/symfony/ux/blob/2.x/ux.symfony.com/bin/compile_svelte.js. + For an example, see https://github.com/symfony/ux/blob/2.x/ux.symfony.com/assets/svelte/build/build.js. #. Point this library at the "built" controllers directory that contains the final JavaScript files: From ef14465e00e17556ede5a7da476c9ac581869fe1 Mon Sep 17 00:00:00 2001 From: Sait KURT <33868586+xDeSwa@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:01:03 +0300 Subject: [PATCH 41/42] [React] Fix broken Link in docs --- src/React/doc/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/React/doc/index.rst b/src/React/doc/index.rst index 96e16e0aa1e..353f05e19d8 100644 --- a/src/React/doc/index.rst +++ b/src/React/doc/index.rst @@ -126,7 +126,7 @@ requires some extra steps. #. Compile your ``.jsx`` files to pure JavaScript files. This can be done by installing Babel and the ``@babel/preset-react`` preset. Example: - https://github.com/symfony/ux/blob/2.x/ux.symfony.com/package.json + https://github.com/symfony/ux/blob/2.x/ux.symfony.com/assets/react/build/package.json #. Point this library at the "built" controllers directory that contains the final JavaScript files: From d29e4d9fd82af62ed77860bcfa6c42197cb6bfaf Mon Sep 17 00:00:00 2001 From: Dimitar Date: Thu, 24 Oct 2024 11:15:36 +0300 Subject: [PATCH 42/42] Add support for custom actions in `TurboStream` and `TurboStreamResponse` --- src/Turbo/CHANGELOG.md | 1 + src/Turbo/src/Helper/TurboStream.php | 28 ++++++++++++++++++++++ src/Turbo/src/TurboStreamResponse.php | 16 +++++++++++++ src/Turbo/tests/Helper/TurboStreamTest.php | 28 ++++++++++++++++++++++ 4 files changed, 73 insertions(+) diff --git a/src/Turbo/CHANGELOG.md b/src/Turbo/CHANGELOG.md index 872b94307bb..012b15f241e 100644 --- a/src/Turbo/CHANGELOG.md +++ b/src/Turbo/CHANGELOG.md @@ -4,6 +4,7 @@ - Add `` component - Add `` component +- Add support for custom actions in `TurboStream` and `TurboStreamResponse` ## 2.21.0 diff --git a/src/Turbo/src/Helper/TurboStream.php b/src/Turbo/src/Helper/TurboStream.php index daea084e6ab..d3ecdc5b79c 100644 --- a/src/Turbo/src/Helper/TurboStream.php +++ b/src/Turbo/src/Helper/TurboStream.php @@ -86,6 +86,34 @@ public static function refresh(?string $requestId = null): string return \sprintf('', htmlspecialchars($requestId)); } + /** + * Custom action and attributes. + * + * Set boolean attributes (e.g., `disabled`) by providing the attribute name as key with `null` as value. + * + * @param array $attr + */ + public static function action(string $action, string $target, string $html, array $attr = []): string + { + if (\array_key_exists('action', $attr) || \array_key_exists('targets', $attr)) { + throw new \InvalidArgumentException('The "action" and "targets" attributes are reserved and cannot be used.'); + } + + $attrString = ''; + foreach ($attr as $key => $value) { + $key = htmlspecialchars($key); + if (null === $value) { + $attrString .= \sprintf(' %s', $key); + } elseif (\is_int($value) || \is_float($value)) { + $attrString .= \sprintf(' %s="%s"', $key, $value); + } else { + $attrString .= \sprintf(' %s="%s"', $key, htmlspecialchars($value)); + } + } + + return self::wrap(htmlspecialchars($action), $target, $html, $attrString); + } + private static function wrap(string $action, string $target, string $html, string $attr = ''): string { return \sprintf(<< $attr + * + * @return $this + */ + public function action(string $action, string $target, string $html, array $attr = []): static + { + $this->setContent($this->getContent().TurboStream::action($action, $target, $html, $attr)); + + return $this; + } } diff --git a/src/Turbo/tests/Helper/TurboStreamTest.php b/src/Turbo/tests/Helper/TurboStreamTest.php index 263e454effd..b404dca2ac8 100644 --- a/src/Turbo/tests/Helper/TurboStreamTest.php +++ b/src/Turbo/tests/Helper/TurboStreamTest.php @@ -76,4 +76,32 @@ public function testRefreshWithId(): void TurboStream::refresh('a"b') ); } + + public function testCustom(): void + { + $this->assertSame(<< + + + EOHTML, + TurboStream::action('customAction', 'some["selector"]', '
content
', ['someAttr' => 'someValue', 'boolAttr' => null, 'intAttr' => 0, 'floatAttr' => 3.14]) + ); + } + + /** + * @dataProvider customThrowsExceptionDataProvider + * + * @param array $attr + */ + public function testCustomThrowsException(string $action, string $target, string $html, array $attr): void + { + $this->expectException(\InvalidArgumentException::class); + TurboStream::action($action, $target, $html, $attr); + } + + public static function customThrowsExceptionDataProvider(): \Generator + { + yield ['customAction', 'some["selector"]', '
content
', ['action' => 'someAction']]; + yield ['customAction', 'some["selector"]', '
content
', ['targets' => 'someTargets']]; + } }