Skip to content

Commit

Permalink
[StimulusBundle] Normalize Stimulus controller name in event name
Browse files Browse the repository at this point in the history
  • Loading branch information
7-zete-7 authored and Kocal committed Sep 29, 2024
1 parent 1720a47 commit a09e9af
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/StimulusBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
10 changes: 9 additions & 1 deletion src/StimulusBundle/src/Dto/StimulusAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down
87 changes: 87 additions & 0 deletions src/StimulusBundle/tests/Dto/StimulusAttributesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<array{
* controllerName: string,
* actionName: string,
* eventName: ?string,
* expectedAction: string,
* }>
*/
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',
];
}
}

0 comments on commit a09e9af

Please sign in to comment.