From a09e9af3cded5ea7399249e2ebbb5dd967d8422a Mon Sep 17 00:00:00 2001 From: Stanislau Kviatkouski <7zete7@gmail.com> Date: Thu, 12 Sep 2024 23:55:45 +0300 Subject: [PATCH] [StimulusBundle] Normalize Stimulus controller name in event name --- src/StimulusBundle/CHANGELOG.md | 4 + .../src/Dto/StimulusAttributes.php | 10 ++- .../tests/Dto/StimulusAttributesTest.php | 87 +++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/StimulusBundle/CHANGELOG.md b/src/StimulusBundle/CHANGELOG.md index dc18f6526dc..46cc4512108 100644 --- a/src/StimulusBundle/CHANGELOG.md +++ b/src/StimulusBundle/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 2.20.1 + +- Normalize Stimulus controller name in event name + ## 2.14.2 - Fix bug with finding UX Packages with non-standard project structure diff --git a/src/StimulusBundle/src/Dto/StimulusAttributes.php b/src/StimulusBundle/src/Dto/StimulusAttributes.php index 5b91589ae63..bede3116b73 100644 --- a/src/StimulusBundle/src/Dto/StimulusAttributes.php +++ b/src/StimulusBundle/src/Dto/StimulusAttributes.php @@ -75,7 +75,7 @@ public function addAction(string $controllerName, string $actionName, ?string $e $this->actions[] = [ 'controllerName' => $controllerName, 'actionName' => $actionName, - 'eventName' => $eventName, + 'eventName' => null !== $eventName ? $this->normalizeEventName($eventName) : null, ]; foreach ($parameters as $name => $value) { @@ -218,6 +218,14 @@ private function normalizeControllerName(string $controllerName): string return preg_replace('/^@/', '', str_replace('_', '-', str_replace('/', '--', $controllerName))); } + /** + * @see https://stimulus.hotwired.dev/reference/actions + */ + private function normalizeEventName(string $eventName): string + { + return preg_replace_callback('/^.+(?=:)/', fn (array $matches): string => $this->normalizeControllerName($matches[0]), $eventName); + } + /** * Normalize a Stimulus Value API key into its HTML equivalent ("kebab case"). * Backport features from symfony/string. diff --git a/src/StimulusBundle/tests/Dto/StimulusAttributesTest.php b/src/StimulusBundle/tests/Dto/StimulusAttributesTest.php index 17527a3491c..be252c2863f 100644 --- a/src/StimulusBundle/tests/Dto/StimulusAttributesTest.php +++ b/src/StimulusBundle/tests/Dto/StimulusAttributesTest.php @@ -148,4 +148,91 @@ public function testAddAttribute() $this->assertSame('foo="bar baz"', (string) $this->stimulusAttributes); $this->assertSame(['foo' => 'bar baz'], $this->stimulusAttributes->toArray()); } + + /** + * @dataProvider provideAddComplexActionData + */ + public function testAddComplexAction(string $controllerName, string $actionName, ?string $eventName, string $expectedAction): void + { + $this->stimulusAttributes->addAction($controllerName, $actionName, $eventName); + $attributesHtml = (string) $this->stimulusAttributes; + self::assertSame(\sprintf('data-action="%s"', $expectedAction), $attributesHtml); + } + + /** + * @return iterable + */ + public static function provideAddComplexActionData(): iterable + { + // basic datasets + yield 'foo#bar' => [ + 'controllerName' => 'foo', + 'actionName' => 'bar', + 'eventName' => null, + 'expectedAction' => 'foo#bar', + ]; + yield 'baz->foo#bar' => [ + 'controllerName' => 'foo', + 'actionName' => 'bar', + 'eventName' => 'baz', + 'expectedAction' => 'baz->foo#bar', + ]; + + // datasets from https://github.com/hotwired/stimulus + yield 'keydown.esc@document->a#log' => [ + 'controllerName' => 'a', + 'actionName' => 'log', + 'eventName' => 'keydown.esc@document', + 'expectedAction' => 'keydown.esc@document->a#log', + ]; + yield 'keydown.enter->a#log' => [ + 'controllerName' => 'a', + 'actionName' => 'log', + 'eventName' => 'keydown.enter', + 'expectedAction' => 'keydown.enter->a#log', + ]; + yield 'keydown.shift+a->a#log' => [ + 'controllerName' => 'a', + 'actionName' => 'log', + 'eventName' => 'keydown.shift+a', + 'expectedAction' => 'keydown.shift+a->a#log', + ]; + yield 'keydown@window->c#log' => [ + 'controllerName' => 'c', + 'actionName' => 'log', + 'eventName' => 'keydown@window', + 'expectedAction' => 'keydown@window->c#log', + ]; + yield 'click->c#log:once' => [ + 'controllerName' => 'c', + 'actionName' => 'log:once', + 'eventName' => 'click', + 'expectedAction' => 'click->c#log:once', + ]; + + // extended datasets + yield 'vue:mount->foo#bar:passive' => [ + 'controllerName' => 'foo', + 'actionName' => 'bar:passive', + 'eventName' => 'vue:mount', + 'expectedAction' => 'vue:mount->foo#bar:passive', + ]; + yield 'foo--controller-1:baz->bar--controller-2#log' => [ + 'controllerName' => '@bar/controller_2', + 'actionName' => 'log', + 'eventName' => '@foo/controller_1:baz', + 'expectedAction' => 'foo--controller-1:baz->bar--controller-2#log', + ]; + yield 'foo--controller-1:baz@document->bar--controller-2#log:capture' => [ + 'controllerName' => '@bar/controller_2', + 'actionName' => 'log:capture', + 'eventName' => '@foo/controller_1:baz@document', + 'expectedAction' => 'foo--controller-1:baz@document->bar--controller-2#log:capture', + ]; + } }