Skip to content

Commit

Permalink
feature #4536 Make {} optional for the types tag (fabpot)
Browse files Browse the repository at this point in the history
This PR was merged into the 3.x branch.

Discussion
----------

Make {} optional for the types tag

Closes #4532

Commits
-------

dff6fdd Make {} optional for the types tag
  • Loading branch information
fabpot committed Jan 10, 2025
2 parents fb71503 + dff6fdd commit 9d1397a
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 17 deletions.
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],
],
],
];
}
}

0 comments on commit 9d1397a

Please sign in to comment.