Skip to content

Commit

Permalink
bug #1298 [TwigComponent] Allow trailing coma in "props" tags (smnandre)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 2.x branch.

Discussion
----------

[TwigComponent] Allow trailing coma in "props" tags

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | not really
| Issues        | Fix #1286
| License       | MIT

Allow trailing comas in props tag

```twig
{% props
    foo = 'foo',
    bar = 'bar',
%}
```

Commits
-------

799df54 [TwigComponent] Allow trailing coma in "props" tags
  • Loading branch information
weaverryan committed Dec 1, 2023
2 parents ff864e6 + 799df54 commit f60079d
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 3 deletions.
3 changes: 1 addition & 2 deletions src/TwigComponent/src/Twig/PropsTokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,11 @@ public function parse(Token $token): Node
$names[] = $name;

if (!$stream->nextIf(Token::PUNCTUATION_TYPE)) {
$stream->expect(\Twig\Token::BLOCK_END_TYPE);
break;
}
}

$stream->expect(\Twig\Token::BLOCK_END_TYPE);

return new PropsNode($names, $values, $token->getLine(), $token->getValue());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<twig:CommaProps bar="bar" />
<twig:CommaProps foo="FOO" bar="123" foobar="456" />
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

<button {{ attributes.defaults({class: primary ? 'primary' : 'secondary'}) }}>
{{ label }}
</button>
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% props
foo = 'foo',
bar,
foobar = 'foobar',
%}

<p>Hello {{ foo }}, {{ bar }}, and {{ foobar }}</p>
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ public function testComponentPropsOverwriteContextValue(): void
$this->assertStringContainsString('<p>foo</p>', $output);
}

public function testComponentPropsWithTrailingComma(): void
{
$output = self::getContainer()->get(Environment::class)->render('anonymous_component_props_trailing_comma.html.twig');

$this->assertStringContainsString('Hello foo, bar, and foobar', $output);
$this->assertStringContainsString('Hello FOO, 123, and 456', $output);
}

private function renderComponent(string $name, array $data = []): string
{
return self::getContainer()->get(Environment::class)->render('render_component.html.twig', [
Expand Down
148 changes: 148 additions & 0 deletions src/TwigComponent/tests/Integration/Twig/ComponentPropsParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\TwigComponent\Tests\Integration\Twig;

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\UX\TwigComponent\Twig\PropsNode;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Twig\Node\TextNode;
use Twig\Source;

/**
* @author Simon André <[email protected]>
*
* @internal
*/
class ComponentPropsParserTest extends KernelTestCase
{
/**
* @dataProvider providePropsData
*/
public function testPropsData(string $template, array $props, string $text): void
{
$loader = new ArrayLoader(['template' => $template]);

/** @var Environment $twig */
$twig = self::getContainer()->get(Environment::class);
$twig->setLoader($loader);

$tokenStream = $twig->tokenize(new Source($template, 'template'));
$foo = $twig->parse($tokenStream);

$body = $foo->getNode('body')->getNode('0');
$this->assertTrue($body->hasNode(0));

$propsNode = $body->getNode(0);
$this->assertInstanceOf(PropsNode::class, $propsNode);
$this->assertTrue($propsNode->hasAttribute('names'));

foreach ($props as $name => $value) {
$this->assertContains($name, $propsNode->getAttribute('names'));
if (null === $value) {
$this->assertFalse($propsNode->hasNode($name));
continue;
}
$this->assertTrue($propsNode->hasNode($name));
$this->assertTrue($propsNode->getNode($name)->hasAttribute('value'));
$this->assertSame($value, $propsNode->getNode($name)->getAttribute('value'));
}

$this->assertTrue($body->hasNode(1));
$this->assertInstanceOf(TextNode::class, $body->getNode(1));
$this->assertTrue($body->getNode(1)->hasAttribute('data'));
$this->assertSame($text, $body->getNode(1)->getAttribute('data'));
}

/**
* @return iterable<string, array{0: string, 1: array<string, string|int|null>, 2: string}>
*/
public static function providePropsData(): iterable
{
yield 'One Prop with value' => [
'{% props propA=123 %} foo ',
[
'propA' => 123,
],
' foo ',
];
yield 'One Prop without value' => [
'{% props propA %} foo ',
[
'propA' => null,
],
' foo ',
];
yield 'No Props with values' => [
'{% props propA, propB %} foo ',
[
'propA' => null,
'propB' => null,
],
' foo ',
];
yield 'All Props with values' => [
'{% props propA=1, propB=2 %} foo ',
[
'propA' => 1,
'propB' => 2,
],
' foo ',
];
yield 'Some Props with values' => [
'{% props propA, propB=2 %} foo ',
[
'propA' => null,
'propB' => 2,
],
' foo ',
];
yield 'One Prop with value and trailing comma' => [
'{% props propA=123, %} foo ',
[
'propA' => 123,
],
' foo ',
];
yield 'One Prop without value and trailing comma' => [
'{% props propA, %} foo ',
[
'propA' => null,
],
' foo ',
];
yield 'No Props with values and trailing comma' => [
'{% props propA, propB, %} foo ',
[
'propA' => null,
'propB' => null,
],
' foo ',
];
yield 'All Props with values and trailing comma' => [
'{% props propA=1, propB=2, %} foo ',
[
'propA' => 1,
'propB' => 2,
],
' foo ',
];
yield 'Some Props with values and trailing comma' => [
'{% props propA, propB=2, %} foo ',
[
'propA' => null,
'propB' => 2,
],
' foo ',
];
}
}

0 comments on commit f60079d

Please sign in to comment.