Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make {} optional for the types tag #4536

Merged
merged 1 commit into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# 3.19.0 (2025-XX-XX)

* Make `{}` optional for the `types` tag
* Add `LastModifiedExtensionInterface` and implementation in `AbstractExtension` to track modification of runtime classes

# 3.18.0 (2024-12-29)
Expand Down
31 changes: 22 additions & 9 deletions doc/tags/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,23 @@
The ``types`` tag was added in Twig 3.13. This tag is **experimental** and
can change based on usage and feedback.

The ``types`` tag declares the types of template variables.
Use the ``types`` tag to declare the type of a variable:

.. note::
.. code-block:: twig

The types declared in a template are local to that template and must not be
propagated to included templates. This is because a template can be
included from multiple different places, each potentially having different
variable types.
{% types is_correct: 'boolean' %}
{% types score: 'number' %}

Here is how to declare that ``is_correct`` is a boolean, while ``score`` is a
number (see note below):
Or multiple variables:

.. code-block:: twig

{% types
is_correct: 'boolean',
score: 'number',
%}

You can also enclose types with ``{}``:

.. code-block:: twig

Expand All @@ -25,7 +31,7 @@ number (see note below):
score: 'number',
} %}

You can declare variables as optional by adding the ``?`` suffix:
Declare optional variables by adding a ``?`` suffix:

.. code-block:: twig

Expand All @@ -43,6 +49,13 @@ validate variables or their types, this tag enables extensions to do this.
Additionally, :ref:`Twig extensions <creating_extensions>` can analyze these
tags to perform compile-time and runtime analysis of templates.

.. note::

The types declared in a template are local to that template and must not be
propagated to included templates. This is because a template can be
included from multiple different places, each potentially having different
variable types.

.. note::

The syntax for and contents of type strings are intentionally left out of
Expand Down
15 changes: 7 additions & 8 deletions src/TokenParser/TypesTokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ final class TypesTokenParser extends AbstractTokenParser
public function parse(Token $token): Node
{
$stream = $this->parser->getStream();

$types = $this->parseSimpleMappingExpression($stream);

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

return new TypesNode($types, $token->getLine());
Expand All @@ -46,17 +44,15 @@ public function parse(Token $token): Node
*/
private function parseSimpleMappingExpression(TokenStream $stream): array
{
$stream->expect(Token::PUNCTUATION_TYPE, '{', 'A mapping element was expected');

$enclosed = null !== $stream->nextIf(Token::PUNCTUATION_TYPE, '{');
$types = [];

$first = true;
while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) {
while (!($stream->test(Token::PUNCTUATION_TYPE, '}') || $stream->test(Token::BLOCK_END_TYPE))) {
if (!$first) {
$stream->expect(Token::PUNCTUATION_TYPE, ',', 'A type string must be followed by a comma');

// trailing ,?
if ($stream->test(Token::PUNCTUATION_TYPE, '}')) {
if ($stream->test(Token::PUNCTUATION_TYPE, '}') || $stream->test(Token::BLOCK_END_TYPE)) {
break;
}
}
Expand All @@ -78,7 +74,10 @@ private function parseSimpleMappingExpression(TokenStream $stream): array
'optional' => $isOptional,
];
}
$stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened mapping is not properly closed');

if ($enclosed) {
$stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened mapping is not properly closed');
}

return $types;
}
Expand Down
9 changes: 9 additions & 0 deletions tests/TokenParser/TypesTokenParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ public static function getMappingTests(): array
'baz' => ['type' => 'baz', 'optional' => false],
],
],

// without {} enclosing
[
'{% types foo: "foo", bar: "bar" %}',
[
'foo' => ['type' => 'foo', 'optional' => false],
'bar' => ['type' => 'bar', 'optional' => false],
],
],
];
}
}
Loading